Skip to contents

Form

A native form element with consolidated error handling.

Anatomy

Form is composed together with Field. Import the components and place them together:

Examples

Submit with a Server Function

Forms can be submitted with a SvelteKit form action instead of onsubmit. Return the action's errors from fail() and pass them to errors. The demo below mimics the action with onFormSubmit. Connect a form action shows the real +page.server.ts and use:enhance.

Submit form values as a JavaScript object

You can use onFormSubmit instead of the native onsubmit to access form values as a JavaScript object. This is useful when you need to transform the values before submission, or integrate with 3rd party APIs.

When used, preventDefault is called on the native submit event.

Using with Zod

When parsing the schema using schema.safeParse(), the z.flattenError(result.error).fieldErrors data can be used to map the errors to each field's name. The demo below uses Valibot, where v.flatten(result.issues).nested gives the same shape.

API reference

A native form element with consolidated error handling. Renders a <form> element.

form S —
Name
Description

The external owner of form state, such as a SvelteKit remote form. Its attributes and attachment go on the <form>. Fields bind to its fields.

Type
S
enhance function —
Name
Description

Runs once the source has validated a submit, with the source's enhance contract. Call submit() to send it. Without this prop, a successful submit resets the form.

Type
(instance: EnhanceInstanceOf<S>) => unknown
validationMode FormValidationMode 'onSubmit'
Description

When fields should validate. A <Field.Root validationMode> takes precedence.

Type
FormValidationMode
Default
'onSubmit'
errors FormErrors —
Name
Description

Errors supplied from outside the form, usually after a server action. Use bind:errors so clearErrors can drop a key. A new object from the parent replaces the current errors.

Type
FormErrors
Binding
bind:errors
onsubmit EventHandler<SubmitEvent, HTMLFormElement> | null —
Description

Native submit listener. Runs after fields validate and only when no invalid field blocks the submit. Call event.preventDefault() to keep the browser from navigating. This does not skip onFormSubmit.

Type
EventHandler<SubmitEvent, HTMLFormElement> | null
onFormSubmit function —
Description

Called with each named field's value when submit is not blocked. The native submit is cancelled before this runs. With form, the source submits instead, so use enhance.

Type
(formValues: FormValues, eventDetails: FormSubmitEventDetails) => void
onFocusInvalid function | Promise<void> —
Description

Called in place of focusing the first invalid control, after a blocked submit or once errors or source issues arrive. Use it to reveal a control that is hidden, such as one on an inactive step. Form waits for the returned promise and the next DOM update, then focuses the control, also when the callback throws or rejects, unless focus moved while it ran. Keep a hidden step mounted, because a field that is not rendered does not register. With novalidate={false}, the browser handles a native constraint before Form sees the submit, so this is not called for it.

Type
(detail: FormFocusInvalidDetail) => void | Promise<void>
novalidate boolean true
Description

When true (the default), the browser's built-in constraint validation is off. Registered fields still validate through the form. It is set once the form is hydrated, so a page that has not loaded JavaScript keeps the browser's validation.

Type
boolean
Default
true
render Snippet<[props: HTMLFormAttributes, state: FormState, children: Snippet | undefined]> —
Name
Description

Replace the default <form>. Spread props onto the host and render children.

Type
Snippet<[props: HTMLFormAttributes, state: FormState, children: Snippet | undefined]>

Error

Messages no field shows: the source's root issues, issues on paths no mounted Field claims, and errors entries no registered Field has. Renders a <div> element. Sveltery addition with no Base UI counterpart. Before hydration only root issues render, because Fields later in the markup have not claimed their paths yet.

role AriaRole | null 'alert'
Name
Description

The host's role. Focus moves to no field when only form-level messages fail a submit, so the messages are announced.

Type
AriaRole | null
Default
'alert'
children Snippet —
Description

Replaces the messages.

Type
Snippet
render Snippet<[props: HTMLAttributes<HTMLElement>, state: FormErrorState, children: Snippet | undefined]> —
Name
Description

Replace the default <div>. Spread props onto the host element.

Type
Snippet<[props: HTMLAttributes<HTMLElement>, state: FormErrorState, children: Snippet | undefined]>
transitionStatus 'starting' | 'ending' | 'idle' | undefined
Name
transitionStatus
Description

The transition status of the error message.

Type
'starting' | 'ending' | 'idle' | undefined
data-starting-style
Present when the error begins animating in.
data-ending-style
Present when the error is animating out.