Form Field
npx @vyui/cli add form-fieldOverview
VyFormField wraps the headless @vyui/core FormField with the text scaffold around a control: label, description, hint, help, and error. Inside a VyForm it registers itself under name, runs its validators, and renders the resulting error; on its own it still renders the scaffold, but the value and error are yours to supply.
Usage
The default slot receives the field's live value, error, setValue, and disabled. Kit controls do not read the field context on their own, so bind them through the slot.
<script setup lang="ts">
import { VyForm } from '@vyui/kit/form'
import { VyFormField } from '@vyui/kit/form-field'
import { VyInput } from '@vyui/kit/input'
const required = (value: unknown) => (value ? null : 'Email is required')
</script>
<template>
<VyForm :default-values="{ email: '' }">
<VyFormField
name="email"
label="Email"
description="We only use this to send receipts."
help="Work addresses are fine."
required
:validators="[required]"
>
<template #default="{ value, setValue }">
<VyInput
:model-value="value as string"
placeholder="you@example.com"
@update:model-value="setValue"
/>
</template>
</VyFormField>
</VyForm>
</template>
Passing only name to the control forwards the name to the native input; it does not connect the control to the form. Use setValue from the slot.
Manual error
error overrides whatever the surrounding form derived, for server-side validation or a control that validates itself.
<template>
<VyFormField name="code" label="Invite code" :error="serverError">
<template #default="{ value, setValue }">
<VyPinInput :model-value="value as string" @update:model-value="setValue" />
</template>
</VyFormField>
</template>
Slot overrides
label, description, hint, help, and error each take a slot when text alone is not enough. The error slot receives the resolved message.
Features and behavior
namemust be unique inside the parent form and is treated as static — swapping it at runtime orphans the registration.validatorsrun synchronously on submit and stop at the first non-null message.defaultValueseeds the field only when the form'sdefaultValueshas no entry forname.- The error text replaces
helpwhile it is showing; the two never render together. requiredappends a red asterisk to the label, and is presentational — pair it with a validator to actually enforce the field.- Label and hint share one row; description sits under them, and both blocks are omitted when their props and slots are empty.
- Outside a
VyFormthe component throws, because the core primitive injects the form root context.
API
Props
| Prop | Default | Type |
|---|---|---|
defaultValue | — | unknownInitial value when the form's `defaultValues` doesn't supply one. |
description | — | string | undefinedDescription rendered between the label and the control. Overridden by the `description` slot. |
error | — | string | undefinedManual error override. When provided, takes precedence over the validator-derived error from the surrounding `<VyForm>`. |
help | — | string | undefinedHelper text rendered below the control. Hidden when an error is showing. |
hint | — | string | undefinedSmall auxiliary text rendered next to the label (right-aligned). Overridden by the `hint` slot. |
label | — | string | undefinedLabel text rendered above the control. Overridden by the `label` slot. |
name* | — | stringField name — must be unique within the parent `<VyForm>`. |
required | false | boolean | undefinedMarks the field as required — appends a red asterisk to the label. |
size | — | "md" | "sm" | "lg" | "xl" | undefined |
ui | — | Partial<Record<"root" | "label" | "description" | "error" | "wrapper" | "hint" | "help" | "labelWrapper" | "container", ClassNameValue>> | undefined |
validators | — | FormFieldValidator[] | undefinedSynchronous validators (see `@vyui/core`). Stops at the first error. |
Slots
| Slot | Bindings |
|---|---|
default | { value: unknown; error: string | null; setValue: (value: unknown) => void; disabled: boolean; } |
label | {} | undefined |
description | {} | undefined |
hint | {} | undefined |
help | {} | undefined |
error | { error: string; } |
Styling and theming
Override globally through appConfig.ui.formField or per instance with ui.
| UI slot | Purpose |
|---|---|
root | Vertical stack for the whole field. |
wrapper | Label, hint, and description block. |
labelWrapper | Row holding the label and the right-aligned hint. |
label | Label text, plus the required asterisk. |
description | Text between the label and the control. |
container | Wrapper around the control slot. |
error | Error message under the control. |
hint | Auxiliary text next to the label. |
help | Helper text under the control. |
size scales the label, description, hint, help, and error text from sm through xl; it does not size the control itself.
Accessibility
The scaffold is text next to a control, not a native label association — Lynx has no for/id pairing. Screen readers announce the control by its own accessibility-label, so give icon-only or ambiguous controls one that matches the visible label, and repeat the error message there when a field is invalid.