Field
Headless single-control field wiring for labels, descriptions, errors, and shared form-control state.
Field in motion
When to Use
Use Field when one control needs a label and may also need help text, an error, or shared required/disabled state. Use Fieldset when several related controls need one group label, such as radio choices. Use standalone Label when no shared state or description/error wiring is needed.
Features
The behavior Atom owns before your product adds appearance.
- Generates stable control, label, description, and error IDs.
- Shares disabled, required, read-only, and invalid state with Field-aware controls.
- Registers mounted Description and visible Error IDs for
aria-describedby. - Supports built-in or separately composed required/optional indicators.
- Exposes layout orientation as metadata without applying layout.
- Supports custom parts through public context hooks.
- Preserves server relationships when Root composes one wrapper with
asChild. - Bridges a containing Fieldset's disabled, required, invalid, and validation state to its control and reports aggregate Field validity back through that Fieldset before Form.
Import
Anatomy
API Reference
Root
Renders a div by default and provides generated relationships and shared
state. It does not render the actual form control.
| Prop | Type | Default |
|---|---|---|
disabled | boolean | Fieldset state or false |
required | boolean | Fieldset state or false |
readOnly | boolean | false |
invalid | boolean | Fieldset state or false |
validationBehavior | "inline" | "native" | Fieldset/Form value, then automatic |
orientation | "vertical" | "horizontal" | "vertical" |
asChild | boolean | false |
render | RenderProp | - |
Supplying id creates ${id}-control, ${id}-label, ${id}-description,
and ${id}-error; otherwise the base ID is generated.
| Data attribute | Values |
|---|---|
[data-slot] | "field" |
[data-orientation] | "vertical" | "horizontal" |
[data-disabled] | Present when disabled |
[data-required] | Present when required |
[data-readonly] | Present when read only |
[data-invalid] | Present when invalid |
Label
Renders a native label whose htmlFor targets the generated control ID.
State props can override Field state for this Label's metadata only.
| Prop | Type | Default |
|---|---|---|
required | boolean | Field state |
disabled | boolean | Field state |
invalid | boolean | Field state |
readOnly | boolean | Field state |
requiredIndicator | ReactNode | " *" |
optionalIndicator | ReactNode | - |
asChild | boolean | false |
render | RenderProp | - |
Plain-text required indicators are wrapped with aria-hidden. Plain optional
indicators remain available to assistive technology. A React element is used
as provided.
| Data attribute | Values |
|---|---|
[data-slot] | "field-label" |
[data-disabled] | Present when resolved disabled |
[data-required] | Present when resolved required |
[data-readonly] | Present when resolved read only |
[data-invalid] | Present when resolved invalid |
Description
Renders a p with a generated ID. Statically visible parts are included in
server markup; committed registration keeps conditional client parts current.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
render | RenderProp | - |
| Data attribute | Values |
|---|---|
[data-slot] | "field-description" |
Error
Renders only when Field is invalid and match is not false, or when
forceMatch is true. A visible Error participates in aria-describedby.
Error does not announce by default; pass native role="alert" or aria-live
when a newly inserted message should be announced.
| Prop | Type | Default |
|---|---|---|
match | boolean | - |
forceMatch | boolean | false |
asChild | boolean | false |
render | RenderProp | - |
| Data attribute | Values |
|---|---|
[data-slot] | "field-error" |
RequiredIndicator
Renders children for a required Field or fallback otherwise. Use it when
the indicator should be a separate part; set Label's requiredIndicator={null}
to avoid showing two required markers.
| Prop | Type | Default |
|---|---|---|
children | ReactNode | " *" |
fallback | ReactNode | - |
asChild | boolean | false |
render | RenderProp | - |
| ARIA attribute | Values |
|---|---|
aria-hidden | "true" for required content |
| Data attribute | Values |
|---|---|
[data-slot] | "field-required-indicator" | "field-optional-indicator" |
useFieldContext
Returns Field state and generated relationships, or null outside Root.
useRequiredFieldContext
Returns the same context but throws when used outside Root. Use it for a custom part that cannot function without Field.
markFieldPart
Marks a styled public wrapper around Field.Description or Field.Error so
Root can include that wrapper in deterministic server-rendered relationships.
Call it once at module scope after creating the wrapper. The wrapper must
render the matching Atom part and forward its props and ref.
Calling it again with the same kind is safe. Marking one component as two different semantic kinds throws so server inspection cannot silently use the wrong relationship.
Examples
Email With Help and Error
Explicit Optional Indicator
Composed Root
asChild composes Root state and props onto one wrapper. Put Label, the
Field-aware control, Description, and Error directly inside that wrapper so
their generated relationships are present in server markup.
Accessibility
A native validation attempt from a Field-aware control marks Root and the
visible control invalid. A compatible Error part makes omitted behavior resolve
to inline; otherwise it resolves to native. Inline behavior reveals Error,
suppresses only the browser bubble, and focuses the first invalid visible
control. Correcting the value or resetting the form clears native-derived state
without clearing an explicit invalid source.
Field follows native form labeling and the
WAI forms labeling guidance.
Field-aware controls use Label's ID relationship and include mounted
Description and visible Error IDs in aria-describedby. Error uses
an explicit live-region role; do not use invalid state before there is a useful message for
the user. Field owns no keyboard behavior.
Changelog
0.19.0
- Inherited containing Fieldset state and validation behavior and routed Field validity through Fieldset before Form.
0.6.13
- Added validation behavior inheritance, native-invalid aggregation, automatic Error presentation, and visible-control focus support.
0.5.2
- Added
markFieldPartfor styled Description and Error wrappers that must remain statically discoverable during server rendering.
0.5.1
- Made Root
asChildinspect the composed wrapper's immediate children so Description and visible Error relationships remain present in server markup.
0.5.0
- Added server-stable Description/Error relationships with hydration-safe registration and removed the forced alert role from Error.
- Completed Field state, generated ID, and description integration across the supported single-value form controls.
0.1.0
- Initial Atom release.