Field
Connects a label, a description and an error message to one form control. Field generates the ids and sets aria-describedby, aria-invalid, required and disabled on the control, so you do not wire them by hand. Input, Textarea, Select, Checkbox, Radio and Switch read it automatically.
Installation
Add Field to your project with the CK-UI CLI. It copies the source into your project, so the code is yours to change.
- Adds
Field.tsxLabel.tsxto your CK-UI folder (src/components/ck-ui by default)- Installs
@radix-ui/react-label@radix-ui/react-slotif your project does not have them yet
First time with CK-UI in this project? Run npx ck-ui-cli@latest init once before adding components. The installation guide explains what it sets up.
Manual installationInstall the packages and copy the files yourself.
Install the following dependencies
Run these commands in your terminal to install the required packages
Add the Label component
Field imports ./Label, so add this file next to it
Create or update your Field component
Copy this code to create your Field component
Test Your Component
- 1. Add the component to a test page
- 2. Check all props and variants work as expected
- 3. Verify responsive behavior
- 4. Test with different content/data
- 5. Ensure accessibility features work correctly
Description
Field.Description is added to the control's aria-describedby only while it is rendered.
Lowercase letters and numbers. Shown on your public profile.
Validation Error
Set invalid on Field.Root. The control gets aria-invalid and error styling, and Field.Message appears and is added to aria-describedby. Field does not validate: it shows the state you give it.
We send invoices here.
Enter an email address like name@company.com.
Required
required puts the native required attribute on the control (or aria-required where there is no native one) and a visual asterisk on the label.
The asterisk is visual; the input itself is required.
Disabled
disabled disables the control and dims the label.
Contact an owner to change the URL.
Textarea
The character counter's id is added to aria-describedby too.
Up to 160 characters.
Select
The label points at the Select trigger; required and disabled are applied to the Radix Select root.
Used for reports and reminders.
Custom Control
Field.Control applies the same wiring to any single element child.
Applies to notification sounds.
How It Works
- Field.Root creates a context with the control id (from
id, or generated with useId) and the ids of the label, description and message. - Controls call
useFieldControlProps(props). Props you pass yourself win: an explicitid,disabledorrequiredoverrides the Field, and your ownaria-describedbyids are kept and combined. - Field is plain React state with native attributes, so it works in a native
<form>. Passinvalidfrom your own validation logic; Field does not run validation. - Inside a disabled Fieldset, every Field is disabled too.
Accessibility
- Field.Label is a real <label for>, so clicking it focuses the control and the control gets its name from it.
- aria-describedby only lists parts that are rendered, so screen readers never follow a missing id.
- Field.Message has
aria-live="polite", so an error that appears while the user is in the field is announced. - The required asterisk is aria-hidden; the control's required state is what assistive technology reports.
- Error text uses the destructive token and is always shown as text, not color alone.
API Reference
Import with import * as Field from "@/components/ui/Field".
Field.Root
Provides the context. Renders a div.
| Prop | Type | Default | Description |
|---|---|---|---|
id | "string" | "generated" | Id for the control; the other ids derive from it. |
invalid | "boolean" | "false" | Error state: aria-invalid on the control and Field.Message shown. |
required | "boolean" | "false" | required on the control and an asterisk on the label. |
disabled | "boolean" | "false" | Disables the control and dims the label. Also inherited from a disabled Fieldset. |
className | "string" | "undefined" | Additional classes, merged last. |
Field.Label
A label pointing at the control (Label.Root).
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
Field.Description
Help text, referenced by aria-describedby.
| Prop | Type | Default | Description |
|---|---|---|---|
className | "string" | "undefined" | Additional classes, merged last. |
Field.Message
Error text, rendered while the field is invalid and referenced by aria-describedby.
| Prop | Type | Default | Description |
|---|---|---|---|
showWhenValid | "boolean" | "false" | Also render while valid (muted style). |
className | "string" | "undefined" | Additional classes, merged last. |
Field.Control
Applies id, aria-describedby, aria-invalid, required and disabled to its single child.
| Prop | Type | Default | Description |
|---|---|---|---|
children | "ReactElement" | "-" | Exactly one element. |
useFieldControlProps(props, { invalid })
For your own controls: returns props merged with the Field context. useField() returns the raw context (or null outside a Field).
| Prop | Type | Default | Description |
|---|---|---|---|
props | "object" | "-" | The control's props; explicit values win. |
options.invalid | "boolean" | "false" | Extra invalid state from the control itself. |
Used in these blocks
Block families with at least one block built on this component. Each page previews its blocks and lists the components and packages they use.