Skip to content

Field

Combine labels, controls, and help text to compose accessible form fields and grouped inputs.

Code
import {
Button,
Checkbox,
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSeparator,
FieldSet,
Input,
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
Textarea,
} from "@falcon/ui-kit";
const months = [
{ label: "MM", value: null },
{ label: "01", value: "01" },
{ label: "02", value: "02" },
{ label: "03", value: "03" },
{ label: "04", value: "04" },
{ label: "05", value: "05" },
{ label: "06", value: "06" },
{ label: "07", value: "07" },
{ label: "08", value: "08" },
{ label: "09", value: "09" },
{ label: "10", value: "10" },
{ label: "11", value: "11" },
{ label: "12", value: "12" },
];
const years = [
{ label: "YYYY", value: null },
{ label: "2024", value: "2024" },
{ label: "2025", value: "2025" },
{ label: "2026", value: "2026" },
{ label: "2027", value: "2027" },
{ label: "2028", value: "2028" },
{ label: "2029", value: "2029" },
];
export function Example() {
return (
<div className="tw:w-full tw:max-w-md">
<form>
<FieldGroup>
<FieldSet>
<FieldLegend>Payment Method</FieldLegend>
<FieldDescription>
All transactions are secure and encrypted
</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel htmlFor="checkout-7j9-card-name-43j">
Name on Card
</FieldLabel>
<Input
id="checkout-7j9-card-name-43j"
placeholder="Maria Larsen"
required
/>
</Field>
<Field>
<FieldLabel htmlFor="checkout-7j9-card-number-uw1">
Card Number
</FieldLabel>
<Input
id="checkout-7j9-card-number-uw1"
placeholder="1234 5678 9012 3456"
required
/>
<FieldDescription>
Enter your 16-digit card number
</FieldDescription>
</Field>
<div className="tw:grid tw:grid-cols-3 tw:gap-4">
<Field>
<FieldLabel htmlFor="checkout-exp-month-ts6">
Month
</FieldLabel>
<Select items={months}>
<SelectTrigger id="checkout-exp-month-ts6">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{months.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Field>
<Field>
<FieldLabel htmlFor="checkout-7j9-exp-year-f59">
Year
</FieldLabel>
<Select items={years}>
<SelectTrigger id="checkout-7j9-exp-year-f59">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{years.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Field>
<Field>
<FieldLabel htmlFor="checkout-7j9-cvv">CVV</FieldLabel>
<Input id="checkout-7j9-cvv" placeholder="123" required />
</Field>
</div>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<FieldSet>
<FieldLegend>Billing Address</FieldLegend>
<FieldDescription>
The billing address associated with your payment method
</FieldDescription>
<FieldGroup>
<Field orientation="horizontal">
<Checkbox
id="checkout-7j9-same-as-shipping-wgm"
defaultChecked
/>
<FieldLabel
htmlFor="checkout-7j9-same-as-shipping-wgm"
className="tw:font-normal"
>
Same as shipping address
</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
<FieldSet>
<FieldGroup>
<Field>
<FieldLabel htmlFor="checkout-7j9-optional-comments">
Comments
</FieldLabel>
<Textarea
id="checkout-7j9-optional-comments"
placeholder="Add any additional comments"
className="tw:resize-none"
/>
</Field>
</FieldGroup>
</FieldSet>
<Field orientation="horizontal">
<Button type="submit">Submit</Button>
<Button variant="outline" type="button">
Cancel
</Button>
</Field>
</FieldGroup>
</form>
</div>
);
}

A single control with label, helper text, and validation.

Field
├── FieldLabel
├── Input / Textarea / Switch / Select
├── FieldDescription
└── FieldError

Related fields in one group. Use FieldSeparator between sections when needed.

FieldGroup
├── Field
│ ├── FieldLabel
│ ├── Input / Textarea / Switch / Select
│ ├── FieldDescription
│ └── FieldError
├── FieldSeparator
└── Field
├── FieldLabel
└── Input / Textarea / Switch / Select

Semantic grouping with a legend and description, usually containing a FieldGroup.

FieldSet
├── FieldLegend
├── FieldDescription
└── FieldGroup
├── Field
│ ├── FieldLabel
│ ├── Input / Textarea / Switch / Select
│ ├── FieldDescription
│ └── FieldError
└── Field
├── FieldLabel
└── Input / Textarea / Switch / Select
Code
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldSet,
Input,
} from "@falcon/ui-kit";
export function Example() {
return (
<FieldSet className="tw:w-full tw:max-w-xs">
<FieldGroup>
<Field>
<FieldLabel htmlFor="username">Username</FieldLabel>
<Input id="username" type="text" placeholder="mlarsen" />
<FieldDescription>
Choose a unique username for your account.
</FieldDescription>
</Field>
<Field>
<FieldLabel htmlFor="password">Password</FieldLabel>
<FieldDescription>
Must be at least 8 characters long.
</FieldDescription>
<Input id="password" type="password" placeholder="********" />
</Field>
</FieldGroup>
</FieldSet>
);
}
Code
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldSet,
Textarea,
} from "@falcon/ui-kit";
export function Example() {
return (
<FieldSet className="tw:w-full tw:max-w-xs">
<FieldGroup>
<Field>
<FieldLabel htmlFor="feedback">Feedback</FieldLabel>
<Textarea
id="feedback"
placeholder="Your feedback helps us improve..."
rows={4}
/>
<FieldDescription>
Share your thoughts about our service.
</FieldDescription>
</Field>
</FieldGroup>
</FieldSet>
);
}
Code
import {
Field,
FieldDescription,
FieldLabel,
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@falcon/ui-kit";
const items = [
{ label: "Choose department", value: null },
{ label: "Engineering", value: "engineering" },
{ label: "Design", value: "design" },
{ label: "Marketing", value: "marketing" },
{ label: "Sales", value: "sales" },
{ label: "Customer Support", value: "support" },
{ label: "Human Resources", value: "hr" },
{ label: "Finance", value: "finance" },
{ label: "Operations", value: "operations" },
];
export function Example() {
return (
<Field className="tw:w-full tw:max-w-xs">
<FieldLabel htmlFor="department">Department</FieldLabel>
<Select items={items}>
<SelectTrigger id="department">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<FieldDescription>
Select your department or area of work.
</FieldDescription>
</Field>
);
}
Code
import {
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
Input,
} from "@falcon/ui-kit";
export function Example() {
return (
<FieldSet className="tw:w-full tw:max-w-sm">
<FieldLegend>Address Information</FieldLegend>
<FieldDescription>
We need your address to deliver your order.
</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel htmlFor="street">Street Address</FieldLabel>
<Input id="street" type="text" placeholder="123 Main St" />
</Field>
<div className="tw:grid tw:grid-cols-2 tw:gap-4">
<Field>
<FieldLabel htmlFor="city">City</FieldLabel>
<Input id="city" type="text" placeholder="New York" />
</Field>
<Field>
<FieldLabel htmlFor="zip">Postal Code</FieldLabel>
<Input id="zip" type="text" placeholder="90502" />
</Field>
</div>
</FieldGroup>
</FieldSet>
);
}
Code
import {
Checkbox,
Field,
FieldContent,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSeparator,
FieldSet,
} from "@falcon/ui-kit";
export function Example() {
return (
<FieldGroup className="tw:w-full tw:max-w-xs">
<FieldSet>
<FieldLegend variant="label">
Show these sections on the dashboard
</FieldLegend>
<FieldDescription>
Select the sections you want to show on the dashboard.
</FieldDescription>
<FieldGroup className="tw:gap-3">
<Field orientation="horizontal">
<Checkbox
id="dashboard-pref-9k2-agronomy-orders-ljj"
defaultChecked
/>
<FieldLabel
htmlFor="dashboard-pref-9k2-agronomy-orders-ljj"
className="tw:font-normal"
>
Agronomy orders
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="dashboard-pref-9k2-prepay-balances-1yg" />
<FieldLabel
htmlFor="dashboard-pref-9k2-prepay-balances-1yg"
className="tw:font-normal"
>
Prepay balances
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="dashboard-pref-9k2-bookings-fzt" />
<FieldLabel
htmlFor="dashboard-pref-9k2-bookings-fzt"
className="tw:font-normal"
>
Bookings
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="dashboard-pref-9k2-invoices-6l2" />
<FieldLabel
htmlFor="dashboard-pref-9k2-invoices-6l2"
className="tw:font-normal"
>
Invoices
</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<Field orientation="horizontal">
<Checkbox id="dashboard-pref-9k2-sync-records-nep" defaultChecked />
<FieldContent>
<FieldLabel htmlFor="dashboard-pref-9k2-sync-records-nep">
Sync bookings & invoices
</FieldLabel>
<FieldDescription>
Your bookings & invoices are being synced with the grower portal.
You can access them from other devices.
</FieldDescription>
</FieldContent>
</Field>
</FieldGroup>
);
}
Code
import {
Field,
FieldDescription,
FieldLabel,
FieldLegend,
FieldSet,
RadioGroup,
RadioGroupItem,
} from "@falcon/ui-kit";
export function Example() {
return (
<FieldSet className="tw:w-full tw:max-w-xs">
<FieldLegend variant="label">Payment Terms</FieldLegend>
<FieldDescription>
Prepay and early-pay terms offer significant savings.
</FieldDescription>
<RadioGroup defaultValue="prepay">
<Field orientation="horizontal">
<RadioGroupItem value="prepay" id="terms-prepay" />
<FieldLabel htmlFor="terms-prepay" className="tw:font-normal">
Prepay (2% discount)
</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="net-30" id="terms-net-30" />
<FieldLabel htmlFor="terms-net-30" className="tw:font-normal">
Net 30
</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="net-60" id="terms-net-60" />
<FieldLabel htmlFor="terms-net-60" className="tw:font-normal">
Net 60
</FieldLabel>
</Field>
</RadioGroup>
</FieldSet>
);
}
Code
import { Field, FieldLabel, Switch } from "@falcon/ui-kit";
export function Example() {
return (
<Field orientation="horizontal" className="tw:w-fit">
<FieldLabel htmlFor="2fa">Multi-factor authentication</FieldLabel>
<Switch id="2fa" />
</Field>
);
}

Wrap Field components inside FieldLabel to create selectable field groups. This works with RadioGroupItem, Checkbox and Switch components.

Code
import {
Field,
FieldContent,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
FieldTitle,
RadioGroup,
RadioGroupItem,
} from "@falcon/ui-kit";
export function Example() {
return (
<FieldGroup className="tw:w-full tw:max-w-xs">
<FieldSet>
<FieldLegend variant="label">Fulfillment Method</FieldLegend>
<FieldDescription>
Select the fulfillment method for your order.
</FieldDescription>
<RadioGroup defaultValue="pickup">
<FieldLabel htmlFor="pickup-r2h">
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Warehouse Pickup</FieldTitle>
<FieldDescription>
Pick up the order at your local branch.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="pickup" id="pickup-r2h" />
</Field>
</FieldLabel>
<FieldLabel htmlFor="delivery-z4k">
<Field orientation="horizontal">
<FieldContent>
<FieldTitle>Direct Delivery</FieldTitle>
<FieldDescription>
Have the order delivered to the farm.
</FieldDescription>
</FieldContent>
<RadioGroupItem value="delivery" id="delivery-z4k" />
</Field>
</FieldLabel>
</RadioGroup>
</FieldSet>
</FieldGroup>
);
}

Stack Field components with FieldGroup. Add FieldSeparator to divide them.

Code
import {
Checkbox,
Field,
FieldDescription,
FieldGroup,
FieldLabel,
FieldSeparator,
FieldSet,
} from "@falcon/ui-kit";
export function Example() {
return (
<FieldGroup className="tw:w-full tw:max-w-xs">
<FieldSet>
<FieldLabel>Responses</FieldLabel>
<FieldDescription>
Get notified when a grower responds to requests that take time, like
quotes or bulk orders.
</FieldDescription>
<FieldGroup data-slot="checkbox-group">
<Field orientation="horizontal">
<Checkbox id="push" defaultChecked disabled />
<FieldLabel htmlFor="push" className="tw:font-normal">
Push notifications
</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
<FieldSeparator />
<FieldSet>
<FieldLabel>Tasks</FieldLabel>
<FieldDescription>
Get notified when tasks you&apos;ve created have updates.{" "}
<a href="#">Manage tasks</a>
</FieldDescription>
<FieldGroup data-slot="checkbox-group">
<Field orientation="horizontal">
<Checkbox id="push-tasks" />
<FieldLabel htmlFor="push-tasks" className="tw:font-normal">
Push notifications
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="email-tasks" />
<FieldLabel htmlFor="email-tasks" className="tw:font-normal">
Email notifications
</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
</FieldGroup>
);
}
  • Vertical fields: Default orientation stacks label, control, and helper text - ideal for mobile-first layouts.
  • Horizontal fields: Set orientation="horizontal" on Field to align the label and control side-by-side. Pair with FieldContent to keep descriptions aligned.
  • Responsive fields: Set orientation="responsive" for automatic column layouts inside container-aware parents. The orientation switches when the nearest FieldGroup container is at least 28rem (448px) wide.
Code
import {
Button,
Field,
FieldContent,
FieldDescription,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSet,
Input,
} from "@falcon/ui-kit";
export function Example() {
return (
<div className="tw:w-full tw:max-w-lg">
<form>
<FieldSet>
<FieldLegend>Profile</FieldLegend>
<FieldDescription>Fill in your profile information.</FieldDescription>
<FieldGroup>
<Field orientation="responsive">
<FieldContent>
<FieldLabel htmlFor="name">Name</FieldLabel>
<FieldDescription>
Provide your full name for identification
</FieldDescription>
</FieldContent>
<Input id="name" placeholder="Maria Larsen" required />
</Field>
<Field orientation="responsive">
<Button type="submit">Submit</Button>
<Button type="button" variant="outline">
Cancel
</Button>
</Field>
</FieldGroup>
</FieldSet>
</form>
</div>
);
}
  • Add data-invalid to Field to switch the entire block into an error state.
  • Add aria-invalid on the input itself for assistive technologies.
  • Render FieldError immediately after the control or inside FieldContent to keep error messages aligned with the field.
Code
import { Field, FieldError, FieldLabel, Input } from "@falcon/ui-kit";
export function Example() {
return (
<Field data-invalid>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" type="email" aria-invalid />
<FieldError>Enter a valid email address.</FieldError>
</Field>
);
}
  • FieldSet and FieldLegend keep related controls grouped for keyboard and assistive tech users.
  • Field outputs role="group" so nested controls inherit labeling from FieldLabel and FieldLegend when combined.
  • Apply FieldSeparator sparingly to ensure screen readers encounter clear section boundaries.

Groups a form control with its label and supporting content. Renders a <div> element with role="group" and accepts standard <div> props. Set data-invalid to switch the whole field into its invalid state.

orientation?: "horizontal" | "vertical" | "responsive" | null = "vertical"

Layout direction for the field’s control and supporting content.

Groups a field’s title, description, and error message, e.g. beside a control in a horizontal field. Unnecessary when the field has no description. Renders a <div> element and accepts standard <div> props.

Provides supporting detail for a field. Renders a <p> element and accepts standard <p> props.

Displays field validation errors. Renders a <div> element with role="alert" and accepts standard <div> props. Renders nothing without children or a non-empty errors entry.

errors?: ({ message?: string; } | undefined)[]

Validation errors to render when children are not provided. Duplicate messages are dropped; a single message renders as plain text and multiple messages render as a list.

Groups related fields and acts as the container that orientation="responsive" fields respond to. Renders a <div> element and accepts standard <div> props.

Labels a field control. Renders a Label (a <label> element) and accepts standard <label> props. The field does no id generation, so associate the label with its control via htmlFor.

Titles a FieldSet. Renders a <legend> element and accepts standard <legend> props.

variant?: "label" | "legend" = "legend"

Sizing treatment. Use "label" to match FieldLabel sizing, e.g. for nested field sets or checkbox and radio groups.

Separates groups of fields. Renders a <div> element and accepts standard <div> props.

children?: React.ReactNode

Optional content displayed over the separator.

Semantically groups related fields, usually titled with a FieldLegend. Renders a <fieldset> element and accepts standard <fieldset> props.

Titles a field inside FieldContent where a <label> element does not apply, e.g. in a choice card whose FieldLabel wraps the whole field. Renders a <div> element and accepts standard <div> props.