Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(WIP): add docs for Lit with Tanstack forms usage #878

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,35 @@
"to": "framework/solid/guides/linked-fields"
}
]
},
{
"label": "lit",
"children": [
{
"label": "Basic Concepts",
"to": "framework/lit/guides/basic-concepts"
},
{
"label": "Form Validation",
"to": "framework/lit/guides/validation"
},
{
"label": "Async Initial Values",
"to": "framework/lit/guides/async-initial-values"
},
{
"label": "Arrays",
"to": "framework/lit/guides/arrays"
},
{
"label": "Linked Fields",
"to": "framework/lit/guides/linked-fields"
},
{
"label": "UI Libraries",
"to": "framework/lit/guides/ui-libraries"
}
]
}
]
},
Expand Down Expand Up @@ -377,7 +406,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;
}
}
```
4 changes: 4 additions & 0 deletions docs/framework/lit/guides/async-initial-values.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
id: async-initial-values
title: Async Initial Values
---
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<Employee>({
defaultValues: {
firstName: '',
lastName: '',
employed: false,
jobTitle: '',
},
})
```

## 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<Employee>(this, {
defaultValues: {
firstName: '',
lastName: '',
employed: false,
jobTitle: '',
},
})
```

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

```tsx
#form = new TanStackFormController<Employee>(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)
1 change: 1 addition & 0 deletions docs/framework/lit/guides/linked-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Link Two Form Fields Together
4 changes: 4 additions & 0 deletions docs/framework/lit/guides/ui-libraries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
id: ui-libraries
title: UI Libraries
---
4 changes: 4 additions & 0 deletions docs/framework/lit/guides/validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
id: form-validation
title: Form and Field Validation
---
Loading