Skip to main content

Import

import { createForm } from '@tanstack/svelte-form'

Type

function createForm<TFormData>(
  opts?: FormOptions<TFormData>
): SvelteFormApi<TFormData>

Parameters

opts
FormOptions<TFormData>
Configuration options for the form. See FormOptions for details.

Returns

SvelteFormApi
SvelteFormApi<TFormData>
The form API object with the following properties and methods:

Usage

Basic Example

<script lang="ts">
  import { createForm } from '@tanstack/svelte-form'
  
  const form = createForm({
    defaultValues: {
      firstName: '',
      lastName: '',
      age: 0,
    },
    onSubmit: async ({ value }) => {
      console.log('Form submitted:', value)
    },
  })
</script>

<form
  onsubmit={(e) => {
    e.preventDefault()
    e.stopPropagation()
    form.handleSubmit()
  }}
>
  <form.Field name="firstName">
    {#snippet children({ field, state })}
      <input
        value={state.value}
        onblur={field.handleBlur}
        oninput={(e) => field.handleChange(e.currentTarget.value)}
      />
    {/snippet}
  </form.Field>
  
  <button type="submit">Submit</button>
</form>

With Validation

<script lang="ts">
  import { createForm } from '@tanstack/svelte-form'
  
  const form = createForm({
    defaultValues: {
      email: '',
      password: '',
    },
    onSubmit: async ({ value }) => {
      // Handle login
      console.log(value)
    },
  })
</script>

<form
  onsubmit={(e) => {
    e.preventDefault()
    form.handleSubmit()
  }}
>
  <form.Field
    name="email"
    validators={{
      onChange: ({ value }) => {
        if (!value) return 'Email is required'
        if (!value.includes('@')) return 'Invalid email'
        return undefined
      },
    }}
  >
    {#snippet children({ field, state })}
      <input
        type="email"
        value={state.value}
        onblur={field.handleBlur}
        oninput={(e) => field.handleChange(e.currentTarget.value)}
      />
      {#if state.meta.errors.length > 0}
        <em>{state.meta.errors[0]}</em>
      {/if}
    {/snippet}
  </form.Field>
  
  <form.Subscribe>
    {#snippet children(state)}
      <button type="submit" disabled={!state.canSubmit}>
        {state.isSubmitting ? 'Submitting...' : 'Submit'}
      </button>
    {/snippet}
  </form.Subscribe>
</form>

Subscribing to State

<script lang="ts">
  import { createForm } from '@tanstack/svelte-form'
  
  const form = createForm({
    defaultValues: { name: '' },
    onSubmit: async ({ value }) => console.log(value),
  })
  
  // Subscribe to specific state
  const canSubmit = form.useStore((state) => state.canSubmit)
</script>

<div>
  <p>Can Submit: {canSubmit.current}</p>
</div>

TypeScript

The form is fully typed based on your defaultValues:
interface FormData {
  username: string
  email: string
  age: number
}

const form = createForm<FormData>({
  defaultValues: {
    username: '',
    email: '',
    age: 0,
  },
  onSubmit: async ({ value }) => {
    // value is typed as FormData
    console.log(value.username) // ✓ TypeScript knows this is a string
  },
})

See Also

Build docs developers (and LLMs) love