Field
We only use this address for account updates.
Installation
npx @mielui/svelte add field inputyarn dlx @mielui/svelte add field inputbunx @mielui/svelte add field inputUsage
Field connects a label, one control, and its feedback; the control keeps its own value. Spread the attributes from Field.Control onto the component that renders the actual input, button, or other labelable control.
<script lang="ts">
import * as Field from '@mielui/svelte/components/field';
import { Input } from '@mielui/svelte/components/input';
</script>
<Field.Root class="w-full max-w-sm" required>
<Field.Label>Work email</Field.Label>
<Field.Control>
{#snippet children(control)}
<Input
{...control}
type="email"
name="email"
placeholder="you@company.com"
autocomplete="email"
/>
{/snippet}
</Field.Control>
<Field.Description>Weโll only use this address for account updates.</Field.Description>
</Field.Root>
Root creates a stable control ID that Label targets, even before hydration. Mounted descriptions and errors are added to the controlโs aria-describedby alongside any IDs you pass yourself. Omit either part, reorder them, or add more than one description. Set controlId on Root for a custom ID.
Control renders its snippet with no wrapper element. When you write your own wrapper component, forward the supplied attachment to the real control. Input, Textarea, and components with an Input part already do. If the control renders its own label, use only one of the two labels.
Server-rendered feedback
For a form that works without JavaScript, declare the description and error IDs explicitly. Pass describedBy and errorId to Control, and matching IDs to Description and Error. Control appends errorId only while Root is invalid. Keep explicitly referenced parts present whenever those IDs apply; omit the prop when you omit its part. Automatic metadata discovery enhances the mounted form but does not replace these server-rendered relationships.
<Field.Root {issues}>
<Field.Label>Email</Field.Label>
<Field.Control describedBy="email-help" errorId="email-error">
{#snippet children(control)}
<Input {...control} name="email" type="email" />
{/snippet}
</Field.Control>
<Field.Description id="email-help">Your work address.</Field.Description>
<Field.Error id="email-error" />
</Field.Root>Use $props.id() to prefix these IDs when a reusable form can appear more than once.
Validation feedback
Pass issues as a readonly array of objects with a message. Root derives invalid state; Error displays the messages and removes duplicates. SvelteKit remote field issues fit this shape directly. Field does not invent validation rules, submit data, or clear your errors while someone edits.
Letters, numbers, and hyphens. You can change this later.
Error reveals and collapses with the short press motion token, skips movement with reduced motion, and exposes validation text immediately. It announces local updates politely by default. When a focused form-wide summary owns error feedback, set aria-live="off" on Error to avoid repeating the same issues.
Use invalid for externally managed validity. Error can accept its own issues or custom children. Keep the Root validity state in sync when supplying a custom error. Error text describes the control; use Form.Status for a single submission announcement instead of announcing every field as an alert.
A control beside its label
Use horizontal orientation for a checkbox or switch. Content keeps the label and description together while the control remains a separate region.
A short email when thereโs something useful to share.
Composite controls
NumberField.Root owns its value, native name, range, and stepper state. Give Field.Root and NumberField.Root the same disabled and required values, then spread Control attributes onto NumberField.Input. Field.Label replaces NumberField.Label here. OTPField.Root forwards these attributes to its real input, so spread them directly onto that root. Neither example adds a second input or duplicates the label.
Choose between 1 and 12 seats.
Enter the six digits sent to your email.
Groups and required fields
Group supplies spacing between fields; it adds no ARIA role. For a named group of controls or group-wide disabled behavior, use Fieldset instead. Root's disabled and required props reach the control through Field.Control. When Root is required, Field.Label shows a required mark after its text. The mark is hidden from assistive technology, which reads the control's required state instead.
Every part except Control accepts the native attributes of the element it renders: Label renders a label, Description a p, and Root, Error, Content, and Group a div. Root supports bind:element. Compose Form for pending feedback, submission, and a complete remote-form example.
API reference
Field.Root
controlIdstringId shared by the label and the control.
disabledbooleanPrevents interaction and dims the control.
Default
falserequiredbooleanRequires a value before the form can be submitted.
Default
falseinvalidbooleanMarks the field invalid. It defaults to true when there are issues.
issuesreadonly Readonly<{ message: string; }>[]Validation issues for this field.
Default
[]orientation"vertical" | "horizontal"verticalstacks the label and control.horizontalputs them side by side.Default
'vertical'elementBindableHTMLDivElementBindable reference to the DOM element.
Field.Control
describedBystringIds of the description and error, for
aria-describedby.errorIdstringId of the error element.
childrenRequiredSnippet<[FieldControlAttributes]>Content rendered inside.
Field.Error
issuesreadonly Readonly<{ message: string; }>[]Validation issues to list. Defaults to the Root's issues.
Other parts
These parts have no props of their own. They pass HTML attributes and events to their element.
Field.ContentField.DescriptionField.GroupField.Label
pnpm dlx @mielui/svelte add field input