Lit Example: Ui Libraries

ts
import { LitElement, html } from 'lit'
import { customElement } from 'lit/decorators.js'
import '@material/web/textfield/filled-text-field.js'
import '@material/web/checkbox/checkbox.js'
import '@material/web/select/filled-select.js'
import '@material/web/select/select-option.js'
import '@material/web/button/filled-button.js'
import '@material/web/button/outlined-button.js'

import { TanStackFormController } from '@tanstack/lit-form'
import { repeat } from 'lit/directives/repeat.js'
import { styles } from './styles.js'

interface Employee {
  firstName: string
  lastName: string
  employed: boolean
  jobTitle?: string
}

@customElement('tanstack-form-demo')
export class TanStackFormDemo extends LitElement {
  static styles = styles

  #form = new TanStackFormController(this, {
    defaultValues: {
      employees: [] as Employee[],
    },
  })

  render() {
    return html`
      <form
        id="form"
        @submit=${(e: Event) => {
          e.preventDefault()
        }}
      >
        <h1>TanStack Form - Lit Demo</h1>
        ${this.#form.field(
          {
            name: 'employees',
            defaultValue: [],
          },
          (employeesField) => {
            return html`${repeat(
                employeesField.state.value,
                (_, index) => index,
                (_, index) => {
                  return html`
                    ${this.#form.field(
                      {
                        name: `employees[${index}].firstName`,
                        validators: {
                          onChange: ({ value }: { value: string }) => {
                            return value && value.length < 3
                              ? 'Not long enough'
                              : undefined
                          },
                        },
                      },
                      (field) => {
                        return html` <div>
                          <label>First Name</label>
                          <md-filled-text-field
                            type="text"
                            placeholder="First Name"
                            .value="${field.state.value}"
                            @blur="${() => field.handleBlur()}"
                            @input="${(e: Event) => {
                              const target = e.target as HTMLInputElement
                              field.handleChange(target.value)
                            }}"
                            .error="${!!(
                              field.state.meta.isTouched &&
                              !field.state.meta.isValid
                            )}"
                            .errorText="${field.state.meta.errors.join(', ')}"
                          ></md-filled-text-field>
                        </div>`
                      },
                    )}
                    ${this.#form.field(
                      { name: `employees[${index}].lastName` },
                      (lastNameField) => {
                        return html` <div>
                          <label>Last Name</label>
                          <md-filled-text-field
                            type="text"
                            placeholder="Last Name"
                            .value="${lastNameField.state.value}"
                            @blur="${() => lastNameField.handleBlur()}"
                            @input="${(e: Event) => {
                              const target = e.target as HTMLInputElement
                              lastNameField.handleChange(target.value)
                            }}"
                            .error="${!!(
                              lastNameField.state.meta.isTouched &&
                              !lastNameField.state.meta.isValid
                            )}"
                            .errorText="${lastNameField.state.meta.errors.join(
                              ', ',
                            )}"
                          ></md-filled-text-field>
                        </div>`
                      },
                    )}
                    ${this.#form.field(
                      { name: `employees[${index}].employed` },
                      (employedField) => {
                        return html`<div>
                            <label>Employed?</label>
                            <md-checkbox
                              type="checkbox"
                              @input="${() =>
                                employedField.handleChange(
                                  !employedField.state.value,
                                )}"
                              .checked="${employedField.state.value}"
                              @blur="${() => employedField.handleBlur()}"
                            ></md-checkbox>
                          </div>
                          ${employedField.state.value
                            ? this.#form.field(
                                {
                                  name: `employees[${index}].jobTitle`,
                                  defaultValue: '',
                                  validators: {
                                    onChange: ({ value }) => {
                                      return value?.length === 0
                                        ? 'Needs to have a job here'
                                        : null
                                    },
                                  },
                                },
                                (jobTitleField) => {
                                  return html` <div>
                                    <label>Job Title</label>
                                    <md-filled-text-field
                                      type="text"
                                      placeholder="Job Title"
                                      .value="${jobTitleField.state.value}"
                                      @blur="${() =>
                                        jobTitleField.handleBlur()}"
                                      @input="${(e: Event) => {
                                        const target =
                                          e.target as HTMLInputElement
                                        jobTitleField.handleChange(target.value)
                                      }}"
                                      .error="${!jobTitleField.state.meta
                                        .isValid}"
                                      .errorText="${jobTitleField.state.meta.errors.join(
                                        ', ',
                                      )}"
                                    ></md-filled-text-field>
                                  </div>`
                                },
                              )
                            : ''} `
                      },
                    )}
                  `
                },
              )}

              <div>
                <md-outlined-button
                  type="button"
                  @click=${() => {
                    employeesField.pushValue({
                      firstName: '',
                      lastName: '',
                      employed: false,
                    })
                  }}
                >
                  Add employee
                </md-outlined-button>
              </div> `
          },
        )}

        <div>
          <md-filled-button
            type="submit"
            ?disabled=${this.#form.api.state.isSubmitting}
          >
            ${this.#form.api.state.isSubmitting ? html` Submitting` : 'Submit'}
          </md-filled-button>
          <md-outlined-button
            type="button"
            id="reset"
            @click=${() => {
              this.#form.api.reset()
            }}
          >
            Reset
          </md-outlined-button>
        </div>
      </form>
      <pre>${JSON.stringify(this.#form.api.state, null, 2)}</pre>
    `
  }
}
import { LitElement, html } from 'lit'
import { customElement } from 'lit/decorators.js'
import '@material/web/textfield/filled-text-field.js'
import '@material/web/checkbox/checkbox.js'
import '@material/web/select/filled-select.js'
import '@material/web/select/select-option.js'
import '@material/web/button/filled-button.js'
import '@material/web/button/outlined-button.js'

import { TanStackFormController } from '@tanstack/lit-form'
import { repeat } from 'lit/directives/repeat.js'
import { styles } from './styles.js'

interface Employee {
  firstName: string
  lastName: string
  employed: boolean
  jobTitle?: string
}

@customElement('tanstack-form-demo')
export class TanStackFormDemo extends LitElement {
  static styles = styles

  #form = new TanStackFormController(this, {
    defaultValues: {
      employees: [] as Employee[],
    },
  })

  render() {
    return html`
      <form
        id="form"
        @submit=${(e: Event) => {
          e.preventDefault()
        }}
      >
        <h1>TanStack Form - Lit Demo</h1>
        ${this.#form.field(
          {
            name: 'employees',
            defaultValue: [],
          },
          (employeesField) => {
            return html`${repeat(
                employeesField.state.value,
                (_, index) => index,
                (_, index) => {
                  return html`
                    ${this.#form.field(
                      {
                        name: `employees[${index}].firstName`,
                        validators: {
                          onChange: ({ value }: { value: string }) => {
                            return value && value.length < 3
                              ? 'Not long enough'
                              : undefined
                          },
                        },
                      },
                      (field) => {
                        return html` <div>
                          <label>First Name</label>
                          <md-filled-text-field
                            type="text"
                            placeholder="First Name"
                            .value="${field.state.value}"
                            @blur="${() => field.handleBlur()}"
                            @input="${(e: Event) => {
                              const target = e.target as HTMLInputElement
                              field.handleChange(target.value)
                            }}"
                            .error="${!!(
                              field.state.meta.isTouched &&
                              !field.state.meta.isValid
                            )}"
                            .errorText="${field.state.meta.errors.join(', ')}"
                          ></md-filled-text-field>
                        </div>`
                      },
                    )}
                    ${this.#form.field(
                      { name: `employees[${index}].lastName` },
                      (lastNameField) => {
                        return html` <div>
                          <label>Last Name</label>
                          <md-filled-text-field
                            type="text"
                            placeholder="Last Name"
                            .value="${lastNameField.state.value}"
                            @blur="${() => lastNameField.handleBlur()}"
                            @input="${(e: Event) => {
                              const target = e.target as HTMLInputElement
                              lastNameField.handleChange(target.value)
                            }}"
                            .error="${!!(
                              lastNameField.state.meta.isTouched &&
                              !lastNameField.state.meta.isValid
                            )}"
                            .errorText="${lastNameField.state.meta.errors.join(
                              ', ',
                            )}"
                          ></md-filled-text-field>
                        </div>`
                      },
                    )}
                    ${this.#form.field(
                      { name: `employees[${index}].employed` },
                      (employedField) => {
                        return html`<div>
                            <label>Employed?</label>
                            <md-checkbox
                              type="checkbox"
                              @input="${() =>
                                employedField.handleChange(
                                  !employedField.state.value,
                                )}"
                              .checked="${employedField.state.value}"
                              @blur="${() => employedField.handleBlur()}"
                            ></md-checkbox>
                          </div>
                          ${employedField.state.value
                            ? this.#form.field(
                                {
                                  name: `employees[${index}].jobTitle`,
                                  defaultValue: '',
                                  validators: {
                                    onChange: ({ value }) => {
                                      return value?.length === 0
                                        ? 'Needs to have a job here'
                                        : null
                                    },
                                  },
                                },
                                (jobTitleField) => {
                                  return html` <div>
                                    <label>Job Title</label>
                                    <md-filled-text-field
                                      type="text"
                                      placeholder="Job Title"
                                      .value="${jobTitleField.state.value}"
                                      @blur="${() =>
                                        jobTitleField.handleBlur()}"
                                      @input="${(e: Event) => {
                                        const target =
                                          e.target as HTMLInputElement
                                        jobTitleField.handleChange(target.value)
                                      }}"
                                      .error="${!jobTitleField.state.meta
                                        .isValid}"
                                      .errorText="${jobTitleField.state.meta.errors.join(
                                        ', ',
                                      )}"
                                    ></md-filled-text-field>
                                  </div>`
                                },
                              )
                            : ''} `
                      },
                    )}
                  `
                },
              )}

              <div>
                <md-outlined-button
                  type="button"
                  @click=${() => {
                    employeesField.pushValue({
                      firstName: '',
                      lastName: '',
                      employed: false,
                    })
                  }}
                >
                  Add employee
                </md-outlined-button>
              </div> `
          },
        )}

        <div>
          <md-filled-button
            type="submit"
            ?disabled=${this.#form.api.state.isSubmitting}
          >
            ${this.#form.api.state.isSubmitting ? html` Submitting` : 'Submit'}
          </md-filled-button>
          <md-outlined-button
            type="button"
            id="reset"
            @click=${() => {
              this.#form.api.reset()
            }}
          >
            Reset
          </md-outlined-button>
        </div>
      </form>
      <pre>${JSON.stringify(this.#form.api.state, null, 2)}</pre>
    `
  }
}
Subscribe to Bytes

Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.

Bytes

No spam. Unsubscribe at any time.

Subscribe to Bytes

Your weekly dose of JavaScript news. Delivered every Monday to over 100,000 devs, for free.

Bytes

No spam. Unsubscribe at any time.