FormField
The label, hint and error message around a single form control.
<template> <FormField label="Email" name="email"> <Input v-model="state.email" /> </FormField></template>Props
| Name | Type | Default |
|---|---|---|
| label | string | - |
| name | string | - |
| description | string | - |
| error | boolean | string | - |
| required | boolean | false |
| info | string | - |
| ...props | UFormField props (hint, help, size, orientation, errorPattern, ...) | - |
Slots
| Name | Description |
|---|---|
| default | The field's control (Input, Textarea, Select, InputNumber, or anything else), scoped with `error`. |
| label | Overrides the label text, scoped with `label`. |
| description | Overrides the description text, rendered above the control. |
| hint | Overrides the hint text (right-aligned next to the label). With `info` set, it renders after the info icon, still right-aligned. |
| error | Overrides the error text, scoped with `error`. Rendered below the control. |
| help | Overrides the help text shown when there's no error. Rendered below the control. |
Guidelines
Do
- Give it a
namematching the field's key in aForm'sschema/state- that's how a schema validation error gets routed here automatically, no manualerrorprop needed. - Reach for it around any control -
Input,Textarea,Select,Combobox,InputNumber, or a bespoke one - it makes no assumption about what it wraps. - Use
requiredfor a plain visual asterisk only; it doesn't add validation itself - theschemastill needs its own non-optional rule for the field to actually be required.
- Use
descriptionfor context the user needs before they interact with the control - what to enter, an expected format, why the field is being asked at all. It renders above the control, so it's read first. - Use
helpfor supplementary text that only matters after the control, and isn't essential - a reassurance, a privacy note, a format reminder. It renders below the control. - Use a tooltip beside the label (via the
infoprop - an info icon right after the label text, see the "All parts" example) for context that's genuinely optional to read - a definition, a "why we ask this" aside - that would clutter the field if it were always visible asdescription/help. It only appears on hover/focus, so never put anything there a keyboard-only or touch user must see to complete the field correctly. - Don't hand-place an
InfoTooltipin the#labelslot - that slot renders inside the<label>element, and the icon's trigger is a<button>, which is invalid there and leaks "More info" into the control's accessible name.infoputs it beside the label instead.
Don't
- Don't pass a literal
errorstring for a validation failure aFormschema can already express - that duplicates the same message in two places and can drift out of sync. - Don't put anything essential in
help- it's automatically replaced by the error message the moment validation fails on that field, so it's invisible exactly when the field is in its most important state. - Don't reach for a label tooltip when
descriptionorhelpwould do - a tooltip hides its content behind a hover/focus interaction, so it's the wrong choice for anything the user needs to see without extra effort. Use it only for the genuinely-optional aside case above.
Examples
All parts
label, description (above the control), the control itself, help/error (below the control, mutually exclusive - error always wins when both are set), and an info tooltip beside the label via the info prop.
We'll only use this to send you a receipt.
We never share this with third parties.
Must be at least 8 characters
<template> <FormField label="Email" description="We'll only use this to send you a receipt." help="We never share this with third parties." > <Input placeholder="you@example.com" class="w-full" /> </FormField> <FormField label="Password" error="Must be at least 8 characters"> <template #default="{ error }"> <Input type="password" :error="!!error" class="w-full" /> </template> </FormField> <FormField name="webhookUrl" label="Webhook URL" info="Findings post here as soon as a scan finishes." > <Input placeholder="https://example.com/webhook" class="w-full" /> </FormField></template>