# Forms & Inputs ## Contents - Forms use FieldGroup + Field - InputGroup requires InputGroupInput/InputGroupTextarea - Buttons inside inputs use InputGroup + InputGroupAddon - Option sets (2–7 choices) use ToggleGroup - FieldSet + FieldLegend for grouping related fields - Field validation and disabled states --- ## Forms use FieldGroup + Field Always use `FieldGroup` + `Field` — never raw `div` with `space-y-*`: ```tsx Email Password ``` Use `Field orientation="horizontal"` for settings pages. Use `FieldLabel className="sr-only"` for visually hidden labels. **Choosing form controls:** - Simple text input → `Input` - Dropdown with predefined options → `Select` - Searchable dropdown → `Combobox` - Native HTML select (no JS) → `native-select` - Boolean toggle → `Switch` (for settings) or `Checkbox` (for forms) - Single choice from few options → `RadioGroup` - Toggle between 2–5 options → `ToggleGroup` + `ToggleGroupItem` - OTP/verification code → `InputOTP` - Multi-line text → `Textarea` --- ## InputGroup requires InputGroupInput/InputGroupTextarea Never use raw `Input` or `Textarea` inside an `InputGroup`. **Incorrect:** ```tsx ``` **Correct:** ```tsx import { InputGroup, InputGroupInput } from "@/components/ui/input-group" ``` --- ## Buttons inside inputs use InputGroup + InputGroupAddon Never place a `Button` directly inside or adjacent to an `Input` with custom positioning. **Incorrect:** ```tsx
``` **Correct:** ```tsx import { InputGroup, InputGroupInput, InputGroupAddon } from "@/components/ui/input-group" ``` --- ## Option sets (2–7 choices) use ToggleGroup Don't manually loop `Button` components with active state. **Incorrect:** ```tsx const [selected, setSelected] = useState("daily")
{["daily", "weekly", "monthly"].map((option) => ( ))}
``` **Correct:** ```tsx import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group" Daily Weekly Monthly ``` Combine with `Field` for labelled toggle groups: ```tsx Theme Light Dark System ``` > **Note:** `defaultValue` and `type`/`multiple` props differ between base and radix. See [base-vs-radix.md](./base-vs-radix.md#togglegroup). --- ## FieldSet + FieldLegend for grouping related fields Use `FieldSet` + `FieldLegend` for related checkboxes, radios, or switches — not `div` with a heading: ```tsx
Preferences Select all that apply. Dark mode
``` --- ## Field validation and disabled states Both attributes are needed — `data-invalid`/`data-disabled` styles the field (label, description), while `aria-invalid`/`disabled` styles the control. ```tsx // Invalid. Email Invalid email address. // Disabled. Email ``` Works for all controls: `Input`, `Textarea`, `Select`, `Checkbox`, `RadioGroupItem`, `Switch`, `Slider`, `NativeSelect`, `InputOTP`.