Skip to content

Commit

Permalink
docs: add additional docs for Lit (#878)
Browse files Browse the repository at this point in the history
* chore: pulling

* feat: add quickstart and guide for lit docs

* feat: add lit arrays docs

* feat: add lit arrays docs

* feat: add basic concepts docs

* chore: pulling

* feat: add lit docs

* docs: get PR to stable place

---------

Co-authored-by: Corbin Crutchley <[email protected]>
  • Loading branch information
tobySolutions and crutchcorn authored Mar 1, 2025
1 parent d5e06c7 commit 78be5bd
Show file tree
Hide file tree
Showing 9 changed files with 346 additions and 35 deletions.
Empty file modified LICENSE
100644 → 100755
Empty file.
Empty file modified codecov.yml
100644 → 100755
Empty file.
15 changes: 14 additions & 1 deletion docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,19 @@
"to": "framework/solid/guides/linked-fields"
}
]
},
{
"label": "lit",
"children": [
{
"label": "Basic Concepts",
"to": "framework/lit/guides/basic-concepts"
},
{
"label": "Arrays",
"to": "framework/lit/guides/arrays"
}
]
}
]
},
Expand Down Expand Up @@ -385,7 +398,7 @@
},
{
"label": "Classes / TanStackFormController",
"to": "framework/lit/reference/classes/tanstackformcontroller"
"to": "framework/lit/reference/tanstackformcontroller"
}
]
},
Expand Down
181 changes: 181 additions & 0 deletions docs/framework/lit/guides/arrays.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
---
id: arrays
title: Arrays
---

TanStack Form supports arrays as values in a form, including sub-object values inside of an array.

# Basic Usage

To use an array, you can use `field.state.value` on an array value, as in:

```ts
export class TestForm extends LitElement {
#form = new TanStackFormController(this, {
defaultValues: {
people: [] as Array<{ name: string; age: string }>,
},
})
render() {
return html`
<form
id="form"
@submit=${(e: Event) => {
e.preventDefault()
}}
>
<h1>Please enter your details</h1>
${this.#form.field(
{
name: `people`,
},
(peopleField) => {
return html`${repeat(
peopleField.state.value,
(_, index) => index,
(_, index) => {
return html` // ... `
},
)} `
},
)}
</form>
`
}
}
```

This will generate the mapped HTML every time you run pushValue on the field:


```html
<div class="container">
<button
type="button"
@click=${() => {
peopleField.pushValue({name: "",age: ""})
}}>
Add Person
</button>
</div>
```

Finally, you can use a subfield like so:

```ts
return html`
${this.#form.field(
{
name: `people[${index}].name`,
},
(field) => {
return html`
<input
type="text"
placeholder="Name"
.value="${field.state.value}"
@input="${(e: Event) => {
const target = e.target as HTMLInputElement;
field.handleChange(target.value);
}}"
/>
`;
},
)}
`
```


## Full Example


```typescript
export class TestForm extends LitElement {
#form = new TanStackFormController(this, {
defaultValues: {
people: [] as Array<{ name: string}>,
},
});
render() {
return html`
<form
id="form"
@submit=${(e: Event) => {
e.preventDefault();
}}
>
<h1>Please enter your details</h1>
${this.#form.field(
{
name: `people`,
},
(peopleField) => {
return html`${repeat(
peopleField.state.value,
(_, index) => index,
(_, index) => {
return html`
${this.#form.field(
{
name: `people[${index}].name`,
},
(field) => {
return html` <div>
<div class="container">
<label>Name</label>
<input
type="text"
placeholder="Name"
.value="${field.state.value}"
@input="${(e: Event) => {
const target = e.target as HTMLInputElement;
field.handleChange(target.value);
}}"
/>
</div>
</div>`;
}
)}
`;
}
)}
<div class="container">
<button
type="button"
@click=${() => {
peopleField.pushValue({
name: "",
});
}}
>
Add Person
</button>
</div> `;
}
)}
<div class="container">
<button type="submit" ?disabled=${this.#form.api.state.isSubmitting}>
${this.#form.api.state.isSubmitting ? html` Submitting` : "Submit"}
</button>
<button
type="button"
id="reset"
@click=${() => {
this.#form.api.reset();
}}
>
Reset
</button>
</div>
</form>
`;
}

declare global {
interface HTMLElementTagNameMap {
"test-form": TestForm;
}
}
```
99 changes: 99 additions & 0 deletions docs/framework/lit/guides/basic-concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
id: basic-concepts
title: Basic Concepts and Terminology
---

This page introduces the basic concepts and terminology used in the `@tanstack/lit-form` library. Familiarizing yourself with these concepts will help you better understand and work with the library and its usage with Lit.

## Form Options

You can create options for your form so that it can be shared between multiple forms by using the `formOptions` function.

For Example:

```tsx
const formOpts = formOptions({
defaultValues: {
firstName: '',
lastName: '',
employed: false,
jobTitle: '',
} as Employee,
})
```

## Form Instance

A Form Instance is an object that represents an individual form and provides methods and properties for working with the form. You create a form instance using the `TanStackFormController` interface provided by `@tanstack/lit-form`. The `TanStackFormController` is instantiated with the current form's (`this`) class and some default form options. It initializes the form state, handles form submission, and provides methods to manage form fields and their validation.

```tsx
#form = new TanStackFormController(this, {
defaultValues: {
firstName: '',
lastName: '',
employed: false,
jobTitle: '',
} as Employee,
})
```

You may also create a form instance without using `formOptions` by using the standalone `TanStackFormController` API:

```tsx
#form = new TanStackFormController(this, {
...formOpts,
})
```

## Field

A Field represents a single form input element, such as a text input or a checkbox. Fields are created using the `field(FieldOptions, callback)` provided by the form instance. The component accepts a `FieldOptions` object and a callback function that receives a `FieldApi` object. This object provides methods to get the current value of the field, handle input changes, and handle blur events.

For Example:

```ts
${this.#form.field(
{
name: `firstName`,
validators: {
onChange: ({ value }) =>
value.length < 3 ? "Not long enough" : undefined,
},
},
(field: FieldApi<Employee, "firstName">) => {
return html` <div>
<label class="first-name-label">First Name</label>
<input
id="firstName"
type="text"
class="first-name-input"
placeholder="First Name"
@blur="${() => field.handleBlur()}"
.value="${field.state.value}"
@input="${(event: InputEvent) => {
if (event.currentTarget) {
const newValue = (event.currentTarget as HTMLInputElement).value;
field.handleChange(newValue);
}
}}"
/>
</div>`;
},
)}
```

## Field State

Each field has its own state, which includes its current value, validation status, error messages, and other metadata. You can access a field's state using its `field.state` property.

```tsx
const { value, meta: { errors, isValidating } } = field.state
```

There are three field states can be very useful to see how the user interacts with a field. A field is _"touched"_ when the user clicks/tabs into it, _"pristine"_ until the user changes value in it, and _"dirty"_ after the value has been changed. You can check these states via the `isTouched`, `isPristine` and `isDirty` flags, as seen below.

```tsx
const { isTouched, isPristine, isDirty } = field.state.meta
```

![Field states](https://raw.githubusercontent.com/TanStack/form/main/docs/assets/field-states.png)
Loading

0 comments on commit 78be5bd

Please sign in to comment.