Field
Label, description and error wiring for any control, plus a standalone Label.
Build every pull request on its own URL.
New projects deploy here unless they say otherwise.
Builds that can run at once across the team.
Installation
npx shadcn@latest add https://neonkit.heyaadi.com/r/field.jsonUsage
import { Field } from "@/components/ui/field"
import { Switch } from "@/components/ui/switch"
<Field orientation="horizontal" label="Preview deployments" description="Build every pull request on its own URL.">
<Switch defaultChecked />
</Field>Examples
In a form
Every NeonKit control submits under its name and goes back to its starting value on reset. Required ones stop an empty submit with the browser's own message. Send it empty, then fill it in.
Custom control
A control whose focusable parts sit inside a wrapper reads its wiring from useFieldControl() and spreads it onto the group.
Validation
Pass error to swap the description for a message. The field turns red, the control gets aria-invalid, and required shows a neon dot.
Building blocks
Label, FieldDescription and FieldError on their own, for layouts Field doesn't cover, like an action beside the label.
API reference
Field
Wraps a single control element and clones it with id, aria-describedby, aria-invalid and required. Also accepts native div attributes, which go to the outer block.
| Prop | Type | Default |
|---|---|---|
label | ReactNodeVisible label. Points at the control with htmlFor, or aria-labelledby for controls a label can't target. | None |
description | ReactNodeHelper text under the control. | None |
error | ReactNodeRed invalid state and message. Replaces description. Pass true for the state without a message. | None |
required | booleanShows a neon dot after the label and sets required on the control. | false |
id | stringThe control's id. Defaults to the child's own id, then a generated one. | None |
orientation | "vertical"Horizontal puts the label and message on the left and the control on the right. Suits switches and other compact controls. | "vertical" |
size | "sm"Label size. Match it to the control's size. | "md" |
color | NeonColorSets --neon-accent for the control inside. Red while error is set. | inherited |
children | ReactElementThe control. One element; it receives the wiring as props. | None |
useFieldControl
Returns the props a custom control inside a Field should spread onto its focusable element or group. Returns an empty object outside a Field.
| Prop | Type | Default |
|---|---|---|
id | stringMatches the label's htmlFor. | None |
aria-labelledby | stringThe label's id, for elements a label can't target. | None |
aria-describedby | stringThe description or error message id. | None |
aria-invalid | trueSet while the field has an error. | None |
required | trueSet when the field is required. Map it to aria-required if your role supports it. | None |
Label
Native label with the same type scale as Input, Select and Textarea.
| Prop | Type | Default |
|---|---|---|
htmlFor | stringThe control's id. Inside a Field it defaults to the field's control. | None |
required | booleanShows the neon dot. Set required on the control as well so it is announced. | false |
size | "sm"Text size. | "md" |
FieldDescription
Helper text paragraph. Give it an id and point the control's aria-describedby at it.
| Prop | Type | Default |
|---|---|---|
id | stringReferenced by the control's aria-describedby. | None |
FieldError
Red message paragraph. Renders nothing when it has no children.
| Prop | Type | Default |
|---|---|---|
id | stringReferenced by the control's aria-describedby. | None |
Accessibility
- Native inputs, selects, textareas and buttons are labelled with htmlFor; other controls get aria-labelledby, so a slider thumb or a custom group is still named.
- Clicking the label of a control that a label can't focus moves focus to its first focusable part.
- The description or error is linked with aria-describedby, merged with any aria-describedby the control already has.
- The required dot is decorative. Field puts required on the control so assistive tech announces it.
- NeonKit inputs that already take label, description and error props don't need a Field; use it for everything else.