Field
The chrome around a control — label, description, helper and error text, wired together — and the fieldset that groups several of them under one legend.
One line — it is what the board shows and what a party quotes back.
Usage
import { Field, FieldDescription, FieldLabel } from "@kanzo-tech/ui";<Field invalid>
<FieldLabel>Contract id</FieldLabel>
<Input />
<FieldError>Contract ids are Q- followed by four figures.</FieldError>
</Field>Anatomy
FieldSet
├── FieldLegend
├── FieldDescription
├── FieldGroup
│ └── Field
│ ├── FieldLabel
│ │ └── FieldRequiredIndicator
│ ├── FieldContent
│ │ └── FieldTitle
│ ├── <control>
│ ├── FieldDescription
│ ├── FieldHelper
│ ├── FieldError
│ └── FieldSeparator
├── FieldSetHelper
└── FieldSetErrorOrientation
vertical stacks label above control, horizontal puts them on one line, and responsive
starts vertical and becomes horizontal once the surrounding FieldGroup container is wide
enough — the switch is a container query, so a field in a narrow panel stays stacked.
Invalid
invalid on the root is what colours the label, the control and FieldError at once, and
FieldError only renders while the field is invalid.
Helper tone
FieldHelper is the text wired into the control's aria-describedby, and it takes a tone:
muted (the default), info or warning. Use one for a message the value survives — a warning
that a P.O. box cannot be delivered to, a note about what the field will do — and keep
FieldError for what blocks. Ark gives every helper the same id, so a field has one; put a second
line in FieldDescription.
Shown to the people you share with.
Changing it does not rename past exports.Columns
FieldGroup stacks its fields. Give it columns and it lays them out in a grid instead: one to
four equal columns, or "auto" to fit as many as the width allows. A responsive count is a class of
your own — columns={1} with sm:grid-cols-2 is one column on a phone and two beyond it — and a
field that should take the whole row takes col-span-full. It is a prop on a part that already
existed, not a Grid component.
A Field with orientation="responsive" switches on the width of the group, not of its cell,
so inside a narrow column it will still go horizontal; use vertical in a grid.
Required
Optional
FieldRequiredIndicator is the one part that marks either kind of field. On a required field it
renders the asterisk; on any other it renders its fallback, so a form that wants optional fields
called out passes the words once and never writes "(optional)" into a label. The asterisk is hidden
from assistive technology, because the control's required already announces it; the fallback is
read as part of the label, because nothing else says a field is optional. The words are yours —
the library ships no copy.
Disabled
Field set
FieldSet renders a real fieldset/legend, so a group of related fields is announced as a
group rather than as loose controls.
FieldLegend defaults to variant="legend" — a section heading at text-base. Use
variant="label" when the group is one question with several controls (a checkbox group, a
radio group), so its legend reads at the same size as a FieldLabel rather than as a heading
above it.
Messages for the whole group
FieldSetHelper and FieldSetError are the group's own messages, and they are not the same
parts as FieldHelper / FieldError: those belong to one control and are wired into that
control's aria-describedby, while these are wired into the fieldset's, so a screen reader
announces them for the group rather than on whichever field happens to be focused. Like
FieldError, FieldSetError renders only while its root is invalid, so it can stay in the
tree unconditionally.
One asymmetry worth knowing, because it is Ark's and not ours: disabled on a FieldSet
does reach every Field inside it — a real <fieldset disabled> disables its controls, and
Ark's Field reads the fieldset's disabled as its default. invalid does not cascade; it
marks the set and reveals FieldSetError, but each Field keeps its own invalid. Group-level
and field-level validity are separate claims, so set both if you mean both.
API Reference
Field
| Prop | Type | Default |
|---|---|---|
orientation | "vertical" | "horizontal" | "responsive" | "vertical" |
reverse | boolean | false |
Extends Field.Root from Ark, so invalid, disabled, required, readOnly and id pass
through.
FieldHelper
| Prop | Type | Default |
|---|---|---|
tone | "muted" | "info" | "warning" | "muted" |
Extends Field.HelperText from Ark.
FieldGroup
| Prop | Type | Default |
|---|---|---|
columns | 1 | 2 | 3 | 4 | "auto" | stacked |
FieldSet
Extends Fieldset.Root from Ark, so disabled, invalid and id pass through.
FieldLegend
| Prop | Type | Default |
|---|---|---|
variant | "legend" | "label" | "legend" |
Extends Fieldset.Legend from Ark, and renders the real legend.
FieldSetHelper
Muted supporting text for the group, wired into the fieldset's aria-describedby.
FieldSetError
Destructive message for the group; renders only while the FieldSet is invalid.