Skip to contents

Forms

A guide to building forms with Sveltery Base components.

Sveltery Base form control components extend the native constraint validation API so you can build forms for collecting user input or providing control over an interface. They also integrate seamlessly with third-party libraries like Superforms and TanStack Form.

Must be 3 or more characters long

Enter a registry URL with optional tags

Server type
Scaling threshold
20% – 80%
Storage type
Allowed network protocols

Naming form controls

Form controls must have an accessible name in order to be recognized by assistive technologies. Use the label strategy below for each control type.

Input controls

Use <Field.Label> or a native <label> to label the following controls:

  • Input
  • NumberField
  • OTPField
  • Autocomplete
  • Combobox (input outside popup)
  • Checkbox
  • Radio
  • Switch

You can implicitly label <Checkbox>, <Radio> and <Switch> components by enclosing them with <Field.Label>:

Implicitly labeling a switch

Trigger-based controls

  • Combobox (input inside popup): use <Combobox.Label>.
  • Select: use <Select.Label>.
  • Slider: use <Slider.Label>. For multi-thumb sliders, also add an aria-label on each <Slider.Thumb> to distinguish the thumbs.

Fallback

If no visible label is rendered, provide aria-label on the actual form control.

Describing the control

<Field.Description> automatically assigns an accessible description:

Labeling select and slider

Labeling control groups

Compose <Fieldset> when a single label applies to multiple controls, such as a range slider with multiple thumbs or a section that combines several inputs. For checkbox and radio groups, keep the group label in <Fieldset.Legend> and wrap each option with <Field.Item>:

Composing range slider and radio group with fieldset

<Field.Item> should enclose each checkbox or radio option so every control has its own label and description:

Explicitly labeling checkboxes in a checkbox group

Building form fields

Pass the name prop to <Field.Root> to include the wrapped control's value when a parent form is submitted:

Assigning field name to combobox

Submitting data

You can take over form submission using the native onsubmit, or custom onFormSubmit props:

Native submission using onsubmit

When using onFormSubmit, you receive form values as a JavaScript object, with eventDetails provided as a second argument. Additionally, preventDefault() is automatically called on the native submit event:

Submission using onFormSubmit

Constraint validation

Sveltery Base form components support native HTML validation attributes for many validation rules:

  • required specifies a required field.
  • minlength and maxlength specify a valid length for text fields.
  • pattern specifies a regular expression that the field value must match.
  • step specifies an increment that numeric field values must be an integral multiple of.
Defining constraint validation on a text field

Sveltery Base form components use a hidden input to participate in native form submission and validation. To anchor the hidden input near a control so the native validation bubble points to the correct area, ensure the component has been given a name, and wrap controls in a relatively positioned container for best results.

Positioning hidden inputs

Custom validation

You can add custom validation logic by passing a synchronous or asynchronous validation function to the validate prop, which runs after native validations have passed.

Use the validationMode prop to configure when validation is performed:

  • onSubmit (default) validates all fields when the containing <Form> is submitted, afterwards invalid fields revalidate when their value changes.
  • onBlur validates the field when focus moves away.
  • onChange validates the field when the value changes, for example, after each keypress in a text field or when a checkbox is checked or unchecked.

validationDebounceTime can be used to debounce the function in use cases such as asynchronous requests or text fields that validate onChange.

Text input using custom asynchronous validation

Server-side validation

You can pass errors returned by (post-submission) server-side validation to the errors prop, which will be merged into the client-side field state for display.

This should be an object with field names as keys, and an error string or array of strings as the value. Once a field's value changes, any corresponding error in errors will be cleared from the field state.

Displaying errors returned by server-side validation

When using SvelteKit form actions you can return server-side errors from fail() and pass the page's form?.errors to the errors prop. A complete example is available here. A SvelteKit remote form goes to the form prop of <Form> instead, and needs no errors.

Returning errors from a form action

Displaying errors

Use <Field.Error> without children to automatically display the field's native error message when invalid. The match prop can be used to customize the message based on the validity state, and manage internationalization from your application logic:

Customizing error message for a required field

Superforms

Superforms is a popular SvelteKit library that you can integrate with Sveltery Base to externally manage form and field state for your existing components.

Must be 3 or more characters long

Enter a registry URL with optional tags

Server type
Scaling threshold
20% – 80%
Storage type
Allowed network protocols

Initialize the form

Initialize the form with the superForm function, assigning the initial value of each field by their name in the data you pass to defaults:

Initialize a form instance

SPA: true validates and submits in the browser. To validate on the server instead, pass the data that superValidate returns from your load function in place of defaults, as the Superforms docs describe.

Integrate components

Bind each control to the $form store, and forward the field's state from $errors and $tainted to <Field.Root>:

Integrating Superforms with Sveltery Base field

Superforms does not track whether a field was touched, so leave touched out, and <Field.Root> marks the field touched on blur. There is no ref to forward. invalid sets aria-invalid on the control and data-invalid on every part of the field.

Field validation

Specify the validation rules in the schema, pass the schema's adapter to validators, and use the match prop to delegate control of the error rendering:

Defining validation rules and displaying errors

Keep validators when you also validate on the server. Superforms then clears a message as the user edits. Without them, a message from the server stays in $errors, and invalid blocks every later submit.

Submitting data

Attach the enhance action to <Form> with fromAction, and handle the validated values in the onUpdate callback:

Form submission handler

Without SPA, Superforms posts the form to your form action. It skips its own validation on submit, because <Form> sets novalidate, and it posts a submit that <Form> blocked. Cancel that submit in onSubmit:

TanStack Form

TanStack Form is a form library with a function-based API for orchestrating validations that can also be integrated with Sveltery Base.

Initialize the form

Create a form instance with the createForm function, assigning the initial value of each field by their name in the defaultValues option:

Initialize a form instance

Integrate components

Use the <form.Field> component from the form instance to integrate with Sveltery Base components using the children snippet, forwarding the various field properties to the appropriate part:

Integrating TanStack Form with Sveltery Base components

The Sveltery Base <Form> component is not needed when using TanStack Form.

Form validation

To configure a native <form>-like validation strategy:

  1. Use the additional revalidateLogic function and pass it to createForm.
  2. Pass a validation function to the validators.onDynamic option of createForm that returns an error object with keys corresponding to the field names.

This validates all fields when the first submission is attempted, and revalidates any invalid fields when their values change again.

Form-level validators

Field validation

You can pass additional validator functions to individual <form.Field> components to add validations on top of the form-level validators:

Field-level validators

Submitting data

To submit the form:

  1. Pass a submit handler function to the onSubmit option of createForm.
  2. Call form.handleSubmit() from an event handler such as form onsubmit or onclick on a button.
Form submission handler