Skip to content
Sveltier
Mode
Forms

Form and validation

A form that checks every field when it is submitted, focuses the first problem, and otherwise submits as HTML does, so it works with SvelteKit form actions.

Usage

Put fields and a submit Button in a Form. On submit it shows the message of every field. If one is invalid, the form does not submit and the first invalid field takes focus; if all are valid, it calls onsubmit. Without onsubmit, the form submits as HTML does.

Try [email protected] to see the server's answer

At least 8 characters

SignUp.svelte
<script>
  import { Button, Form, TextField } from 'sveltier';

  let email = $state('');
  let password = $state('');
  let sending = $state(false);

  // Called only when every field is valid.
  async function signUp(event) {
    event.preventDefault();
    sending = true;
    await createAccount({ email, password });
    sending = false;
  }
</script>

<Form onsubmit={signUp}>
  <TextField label="Email" type="email" name="email" required bind:value={email} />
  <TextField label="Password" type="password" name="password" minlength={8} required bind:value={password} />
  <Button type="submit" loading={sending}>Create account</Button>
</Form>

When messages show

Each field always knows its own message; validateOn only decides when it shows:

  • "blur" (default): when the user leaves a field they have changed. Tabbing through the form shows nothing.
  • "input": from the first change.
  • "submit": when the form is submitted.

Once a message is shown, it follows every change, so fixing the value clears it at once. Set validateOn on the Form for all its fields, or on one field. What a field checks is described under TextField validation.

With SvelteKit form actions

Give the form method="POST" and pass the action's errors to the fields' error. To submit without a page reload, attach SvelteKit's enhance with fromAction; the Form runs first, so an invalid form is never sent. After a successful submission, enhance resets the form, which also hides the messages.

+page.svelte
<script>
  import { enhance } from '$app/forms';
  import { fromAction } from 'svelte/attachments';
  import { Button, Form, TextField } from 'sveltier';

  // What the form action returned, such as { errors: { email: 'This email is taken' } }.
  let { form } = $props();
</script>

<!-- Without JavaScript the form posts to the action as HTML does; with it, enhance sends it,
     and only once every field is valid. -->
<Form method="POST" action="?/signup" {@attach fromAction(enhance)}>
  <TextField label="Email" type="email" name="email" required error={form?.errors?.email} />
  <TextField label="Password" type="password" name="password" minlength={8} required />
  <Button type="submit">Create account</Button>
</Form>

Methods

Through bind:this, a Form offers three methods:

Methods
<script>
  import { Button, Form } from 'sveltier';
  let form;
</script>

<Form bind:this={form}>…</Form>

<Button onclick={() => form.validate()}>Check</Button>  <!-- shows every message, returns true when valid -->
<Button onclick={() => form.reset()}>Start over</Button>  <!-- every field back to its starting value, messages hidden -->
<Button onclick={() => form.resetValidation()}>Hide messages</Button>

disabled turns off every control inside, Buttons included, for a form the user cannot change. While a submission runs, prefer loading on the submit Button: it keeps focus and ignores a second press.

Accessibility

  • The form has novalidate, so the browser's own bubbles do not appear; the fields show the same messages in the page, linked to their controls.
  • After a submission with errors, focus moves to the first invalid field in document order, which reads out its label and its message.
  • A message that appears while the user is elsewhere is announced politely.

API

NameTypeDefaultDescription
validateOn'blur' | 'input' | 'submit''blur'When the fields show their messages, unless a field sets its own.
disabledbooleanfalseDisables every control inside, Buttons included, for example while a submission runs.
onsubmit(event: SubmitEvent & { currentTarget: EventTarget & HTMLFormElement; }) => void–Called when the form is submitted and every field is valid. Without it, the form submits as HTML does; call event.preventDefault() to handle the submission yourself.
childrenSnippet–The fields and buttons.
classClassValue | null–Classes added after the component's own: a string, an array or an object.
refHTMLFormElement | null–The root element, bindable with bind:ref.