Field
Pairs a control with a label and optional description, as a row or a card.
@garn/ui/fieldDefault
Settings row: label + description + switch.
Sent when someone replies to your thread.
Card
Card appearance.
A Monday summary of everything you missed.
Controls
Same Field with a checkbox and radio items.
You agree to our terms of service and privacy policy.
Free — arrives within the week.
$8 — priority handling and tracking.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add field- Registry
field- Source
- field.tsx
- Deps
class-variance-authority- Registry deps
utilslabel
Import
import { Field } from "@garn/ui/field";Props
Generated from the component's TypeScript types.
appearance- Description
- No description.
- Type
"card" | "plain"- Default
plain
orientation- Description
- No description.
- Type
"end" | "start"- Default
start
childrenRequired- Description
- The control: a Switch, Checkbox, or single RadioGroupItem.
- Type
React.ReactElement<unknown, string | React.JSXElementConstructor<any>>
description- Description
- Optional one-line explanation, wired to the control via `aria-describedby`.
- Type
React.ReactNode
labelRequired- Description
- The setting name — becomes the control's accessible name via `htmlFor`.
- Type
React.ReactNode
size- Description
- Label text size — pair with the control's own `size`.
- Type
"lg" | "md" | "sm"
Plus 279 inherited native <div> attributes.
Styling
Target these data-slots and remap these tokens to restyle without forking the component.
[data-slot="field"]| Property | Token | Tier |
|---|---|---|
cardSurface | --garn-card | semantic |
cardPadding | --garn-pad-panel | semantic · air |
selectedEdge | --garn-brand-solidbrandable | semantic |
descriptionColor | --garn-muted-foreground | semantic |
Overview
Field is the shared control-field: it takes a Switch, Checkbox, or a single RadioGroupItem as its child and lays it beside a label and an optional one-line description, doing the accessible-name (htmlFor) and description (aria-describedby) wiring for you. appearance="card" turns the row into a bordered option card that highlights when its control is checked, and orientation flips between a control-leading row (checkboxes, radios) and a text-leading settings row (the switch on the right). Because it wires by cloning the control, one Field looks and behaves identically whichever control drives it. For a form bound to react-hook-form with validation messages, use Form instead; Field is the lightweight, standalone layout.
Guidelines
Give every Field a label — that IS the control's name. The label is required and is associated by htmlFor, so you don't add a separate aria-label to the control. Add a description only when the effect isn't obvious from the label.
Use card for selectable options, plain for dense settings. A list of option cards (pick-one radios, feature toggles) reads well as card; a long settings screen is calmer as plain rows with a divider. The card's checked-edge highlight only makes sense when one option among several is chosen.
Match orientation to the control. Checkboxes and radios read naturally control-first (start); a switch usually sits at the end of a settings row (end), label on the left. Keep the whole group consistent.
One control per Field. Field clones a single child to wire it. For a group of radios, wrap each RadioGroupItem in its own Field inside one RadioGroup.
Best practices
- Pass exactly one control as children; let Field wire the label + description.
- Use
appearance="card"for pick-one option cards,orientation="end"for switch settings rows.
- Don't add an aria-label to the control — the Field's label already names it.
- Don't put multiple controls in one Field; wrap each in its own Field.
Content guidelines
- Label states what the setting is, in sentence case; the description is one short line, not a paragraph.
- Don't repeat the label in the description.
Accessibility
Enforceable contracts
Pass exactly one control (Switch, Checkbox, or a RadioGroupItem) as children — Field clones it to inject the id + aria-describedby.
when children is not a single control element
- • The Label's htmlFor points at the control's generated id, so the control's accessible name is the label text.
- • A description is given an id and wired onto the control via aria-describedby (preserving any aria-describedby the control already had).
- • Clicking the label toggles the control (native label association); the description is not part of the accessible name.
- Status
- Stable
- Version
v0.3.0- Introduced
v0.2.0
garn doesn't yet record a per-release version history. This reflects the component's current lifecycle state; full changelog entries will appear once the metadata pipeline emits a lifecycle.history field.