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.
<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.
<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:
<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
| Name | Type | Default | Description |
|---|---|---|---|
validateOn | 'blur' | 'input' | 'submit' | 'blur' | When the fields show their messages, unless a field sets its own. |
disabled | boolean | false | Disables 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. |
children | Snippet | – | The fields and buttons. |
class | ClassValue | null | – | Classes added after the component's own: a string, an array or an object. |
ref | HTMLFormElement | null | – | The root element, bindable with bind:ref. |