Field
Accessible, unstyled Field compound primitive for form label, help, and error wiring.
|
|
| Package |
@vizejs/ui/field |
| Maturity |
stable |
| Own the source |
vize lib pull field |
| Requires |
context, field-wiring, form |
| Aliases |
form field, field label, field description, field error message |
| Covers |
React Aria Field, Radix Form Field, Reka UI Form |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { Field, FieldRoot, FieldDescription, FieldErrorMessage, FieldLabel } from "@vizejs/ui/field";
Or copy the source into your project with vize lib pull field (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Email field whose label, help text, and validation error are wired to the native input. -->
<script setup lang="ts">
import { computed, ref } from "vue";
import { Field, FieldDescription, FieldErrorMessage, FieldLabel } from "@vizejs/ui/field";
const email = ref("");
const touched = ref(false);
const errors = computed(() =>
touched.value && !email.value.includes("@")
? [{ name: "email", message: "Enter an email address like [email protected]", path: ["email"] }]
: [],
);
function markTouched(): void {
touched.value = true;
}
</script>
<template>
<Field v-slot="{ fieldProps }" name="email" :errors has-description>
<FieldLabel>Work email</FieldLabel>
<input
v-bind="fieldProps"
v-model="email"
:aria-labelledby="fieldProps['aria-labelledby']"
name="email"
type="email"
autocomplete="email"
@blur="markTouched"
/>
<FieldDescription>We send receipts to this address.</FieldDescription>
<FieldErrorMessage />
</Field>
</template>
API
Field
Source: src/families/form/field/field.vue
Props
| Prop |
Type |
Default |
Description |
as |
PrimitiveAs |
"div" |
Native element, custom element, or component to render. |
id |
string | null |
undefined |
Consumer-owned control id. null and undefined select a deterministic fallback. |
name (required) |
string |
required |
Normalized HTML form field name. |
errors |
readonly FormFieldError[] |
[] |
Full normalized form error list produced by the form helpers. |
invalid |
boolean |
undefined |
Consumer-owned invalid override. undefined derives invalid state from matching errors. |
hasDescription |
boolean |
false |
Whether a FieldDescription is rendered and should join aria-describedby. |
hasErrorMessage |
boolean |
true |
Whether a FieldErrorMessage is rendered while invalid and should be referenced. |
Events
| Event |
Payload |
Description |
invalid-change |
[invalid: boolean, errors: readonly FormFieldError[]] |
Fired after the derived invalid boolean changes. |
Slots
| Slot |
Slot props |
Description |
default |
FieldRootSlotState |
Renders the composed field body with ids, ARIA props, and normalized field state. |
Exposed
| Member |
Type |
Description |
descriptionProps |
— |
|
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
errorMessage |
— |
|
errorMessageProps |
— |
|
errors |
— |
|
fieldProps |
— |
|
id |
— |
|
invalid |
— |
|
labelProps |
— |
|
name |
— |
|
FieldRoot
Source: src/families/form/field/field.vue
Props
| Prop |
Type |
Default |
Description |
as |
PrimitiveAs |
"div" |
Native element, custom element, or component to render. |
id |
string | null |
undefined |
Consumer-owned control id. null and undefined select a deterministic fallback. |
name (required) |
string |
required |
Normalized HTML form field name. |
errors |
readonly FormFieldError[] |
[] |
Full normalized form error list produced by the form helpers. |
invalid |
boolean |
undefined |
Consumer-owned invalid override. undefined derives invalid state from matching errors. |
hasDescription |
boolean |
false |
Whether a FieldDescription is rendered and should join aria-describedby. |
hasErrorMessage |
boolean |
true |
Whether a FieldErrorMessage is rendered while invalid and should be referenced. |
Events
| Event |
Payload |
Description |
invalid-change |
[invalid: boolean, errors: readonly FormFieldError[]] |
Fired after the derived invalid boolean changes. |
Slots
| Slot |
Slot props |
Description |
default |
FieldRootSlotState |
Renders the composed field body with ids, ARIA props, and normalized field state. |
Exposed
| Member |
Type |
Description |
id |
string |
Stable id for the consumer-rendered form control. |
name |
string |
Normalized HTML form field name. |
invalid |
boolean |
Whether this field is currently invalid. |
errors |
readonly FormFieldError[] |
Current normalized errors for this field only. |
errorMessage |
string | undefined |
First current error message for this field. |
fieldProps |
FieldControlProps |
Attributes to bind to the consumer-rendered form control. |
labelProps |
FieldLabelProps |
Attributes bound by FieldLabel. |
descriptionProps |
FieldTextProps |
Attributes bound by FieldDescription. |
errorMessageProps |
FieldTextProps |
Attributes bound by FieldErrorMessage. |
element |
PrimitiveElement | null |
Rendered root element or component instance. |
FieldDescription
Source: src/families/form/field/field-description.vue
Props
| Prop |
Type |
Default |
Description |
as |
PrimitiveAs |
"p" |
Native element, custom element, or component to render. |
Slots
| Slot |
Slot props |
Description |
default |
FieldDescriptionSlotState |
Renders descriptive help text with the resolved description id. |
Exposed
| Member |
Type |
Description |
element |
PrimitiveElement | null |
Rendered description element or component instance. |
FieldErrorMessage
Source: src/families/form/field/field-error-message.vue
Props
| Prop |
Type |
Default |
Description |
as |
PrimitiveAs |
"p" |
Native element, custom element, or component to render. |
forceMount |
boolean |
false |
Keep the error message element in the DOM while the field is valid. |
Slots
| Slot |
Slot props |
Description |
default |
FieldErrorMessageSlotState |
Renders validation text with the resolved error id and current field errors. |
Exposed
| Member |
Type |
Description |
element |
PrimitiveElement | null |
Rendered error message element or component instance. |
invalid |
boolean |
Whether this field is currently invalid. |
message |
string | undefined |
First current error message for this field. |
FieldLabel
Source: src/families/form/field/field-label.vue
Props
| Prop |
Type |
Default |
Description |
as |
PrimitiveAs |
"label" |
Native element, custom element, or component to render. |
Slots
| Slot |
Slot props |
Description |
default |
FieldLabelSlotState |
Renders visible label content with the resolved label and control ids. |
Exposed
| Member |
Type |
Description |
element |
PrimitiveElement | null |
Rendered label element or component instance. |
Behavior
Normative state x input -> outcome table for field.vue, field-label.vue,
field-description.vue, and field-error-message.vue (@vizejs/ui/field).
Every row is proven by the named test in src/families/form/field/field.test.ts
or src/families/form/field/field-ssr.test.ts; compile-only assertions live in
src/families/form/field/field.types.test-d.ts.
| ID |
State |
Input |
Outcome |
Test |
| FC1 |
valid |
render with label and control |
FieldLabel id and for match Field slot fieldProps |
wires label and described-by props through public SFCs |
| FC2 |
valid |
hasDescription with FieldDescription |
control receives the description id in aria-describedby |
wires label and described-by props through public SFCs |
| FC3 |
field error |
matching normalized error by name |
Field becomes invalid, error message renders, and ARIA error props bind |
renders normalized form errors and emits invalid changes |
| FC4 |
forced error |
invalid prop without matching errors |
Field becomes invalid while the message slot remains consumer-owned |
allows direct invalid overrides for native validation |
| FC5 |
invalid |
hasDescription=false |
description element can render, but the control omits its id |
suppresses optional ARIA relations when declared absent |
| FC6 |
invalid |
hasErrorMessage=false |
error element can render, but control omits aria-errormessage |
suppresses optional ARIA relations when declared absent |
| FC7 |
no provider |
Field part rendered outside Field |
setup throws the stable missing-context diagnostic |
rejects field parts outside a Field root |
| FC8 |
SSR |
isolated request renders with IdProvider |
byte-identical control, label, description, and error ids |
SSR test |
| FC9 |
public types |
malformed props and slot/expose misuse |
compilation rejects misuse |
src/families/form/field/field.types.test-d.ts |
Public contract
Field renders data-vize-ui="field", part="root", data-state,
data-invalid, and data-name.
FieldLabel renders data-vize-ui="field-label", part="label",
data-state, data-invalid, and data-name.
FieldDescription renders data-vize-ui="field-description",
part="description", data-state, data-invalid, and data-name.
FieldErrorMessage renders data-vize-ui="field-error-message",
part="error-message", data-state, data-invalid, and data-name while
the field is invalid or forceMount=true.
Field exposes no CSS custom properties and ships no opinionated styles.
hasDescription is the SSR-safe declaration that a description element is
present. FieldDescription does not mutate the parent relation implicitly.
hasErrorMessage is the SSR-safe declaration that an error message element
is present while invalid. Set it to false for native-only invalid state.