Form Components
Form inputs, selects, checkboxes, and form validation components
Form components for building data entry interfaces.
Prerequisites
- Complete the installation
- Import styles:
import '@tetherto/mdk-react-devkit/styles.css'
Components
Core form workflow
Form primitives built on react-hook-form. Use with a useForm() instance.
Pieces
Form— wraps a<form>and providesFormProvidercontext.FormField— wrapsreact-hook-form'sControllerand provides field context.FormItem— layout wrapper that generates IDs for accessibility linking.FormLabel,FormControl,FormDescription,FormMessage— slots.
Notes
- Pre-built field helpers (
FormInput,FormSelect,FormCheckbox,FormDatePicker,FormCascader, etc.) live inform-fields.tsx. - See the directory's README.md and QUICK_REFERENCE.md for the full pattern catalog.
Example
/**
* Runnable example for Form (react-hook-form + zod).
*/
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import {
Button,
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
Input,
} from '@tetherto/mdk-react-devkit'
const schema = z.object({
name: z.string().min(2, 'At least 2 characters'),
email: z.string().email('Must be a valid email'),
})
type FormValues = z.infer<typeof schema>
export const FormExample = () => {
const form = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: { name: '', email: '' },
})
const onSubmit = (values: FormValues) => {
// eslint-disable-next-line no-console
console.log('submit', values)
}
return (
<Form form={form} onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="Operator name" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="ops@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" variant="primary">
Submit
</Button>
</Form>
)
}Related API
Cascader
Two-panel hierarchical selector for picking a leaf value from a nested tree (categories → subcategories → leaf).
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
options | CascaderOption[] | ✓ | - | Hierarchical options to display in the cascader Parent options with children appear in the left panel Child options app… |
value | CascaderValue | CascaderValue[] | undefined | - | Current selected value(s) - For single select: CascaderValue (e.g., ['category', 'option']) - For multiple select: Casc… | |
onChange | ((value: CascaderValue | CascaderValue[] | null) => void) | undefined | - | Callback when selection changes - For single select: receives CascaderValue or null - For multiple select: receives Cas… | |
multiple | boolean | undefined | false | Enable multiple selection mode - true: Shows checkboxes, allows multiple selections, displays selected items as tags -… | |
placeholder | string | undefined | 'Select...' | Placeholder text shown in the input when no selections are made | |
disabled | boolean | undefined | false | Disable the entire cascader (input and all options) | |
className | string | undefined | - | Custom className for the root cascader element | |
dropdownClassName | string | undefined | - | Custom className for the dropdown panels container |
Checkbox
Checkbox component with full customization
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | CheckboxSize | undefined | 'md' | Size variant of the checkbox | |
color | "success" | "warning" | "error" | "primary" | "default" | undefined | 'primary' | Color variant when checked | |
radius | BorderRadius | undefined | 'none' | Border radius variant | |
className | string | undefined | - | Custom className for the root element | |
indicatorClassName | string | undefined | - | Custom className for the indicator element | |
onCheckedChange | (((checked: CheckedState) => void) & ((checked: CheckedState) => void)) | undefined | - | Callback when the checked state changes |
CurrencyToggler
CurrencyToggler component for switching between currencies
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
value | string | ✓ | - | - |
className | string | undefined | - | - | |
currencies | (string | CurrencyItem)[] | ✓ | - | - |
onChange | (currency: string) => void | ✓ | - | - |
DatePicker
Single-date selection component built on react-day-picker with the MDK dark theme. Controlled via selected / onSelect.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
selected | Date | undefined | - | Currently selected date | |
onSelect | ((date: Date | undefined) => void) | undefined | - | Callback when date changes | |
placeholder | string | undefined | "Pick a date" | Placeholder text when no date is selected | |
dateFormat | string | undefined | "MM/dd/yyyy" | Date format for display | |
disabled | (boolean & (Matcher | Matcher[])) | undefined | false | Whether the picker is disabled | |
triggerClassName | string | undefined | - | Custom className for the trigger button | |
calendarClassName | string | undefined | - | Custom className for the calendar |
DateRangePicker
Date-range selection component with preset shortcuts (last 7/14/30/90 days) and a modal interface. Controlled via selected / onSelect.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
selected | DateRange | undefined | - | Selected date range | |
onSelect | ((range: DateRange | undefined) => void) | undefined | - | Callback when date range changes | |
placeholder | string | undefined | "Pick a date range" | Placeholder text when no range is selected | |
dateFormat | string | undefined | "MM/dd/yyyy" | Date format for display | |
disabled | (boolean & (Matcher | Matcher[])) | undefined | false | Whether the picker is disabled | |
showPresets | boolean | undefined | true | Whether to show preset buttons | |
presets | PresetItem[] | undefined | - | Custom preset items | |
allowFutureDates | boolean | undefined | false | Whether to allow future dates | |
triggerClassName | string | undefined | - | Custom className for the trigger button | |
calendarClassName | string | undefined | - | Custom className for the calendar | |
modalClassName | string | undefined | - | Custom className for the modal |
Form
React Hook Form provider wrapper. Pass the result of useForm() as form and render fields via [**FormField**](/reference/ui/components/forms/#formfield) / [**FormItem**](/reference/ui/components/forms/#formitem) / [**FormLabel**](/reference/ui/components/forms/#formlabel) / [**FormControl**](/reference/ui/components/forms/#formcontrol) / [**FormMessage**](/reference/ui/components/forms/#formmessage).
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
form | UseFormReturn<TFieldValues> | ✓ | - | - |
children | React.ReactNode | ✓ | - | - |
FormCascader
Pre-built Cascader field component with integrated form state. Perfect for hierarchical selections like categories and subcategories.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
options | CascaderOption[] | ✓ | - | - |
multiple | boolean | undefined | - | - | |
cascaderProps | Omit<CascaderProps & React.RefAttributes<HTMLDivElement>, "onChange" | "value" | "options" | "placeholder"> | undefined | - | - |
FormCheckbox
Pre-built Checkbox field component with integrated form state.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
checkboxProps | ({ size?: CheckboxSize | undefined; color?: ComponentColor | undefined; radius?: BorderRadius | undefined; className?: string | undefined; indicatorClassName?: string | undefined; onCheckedChange?: ((checked: CheckedState) => void) | undefi… /* see source */ | - | - | |
layout | "row" | "column" | undefined | - | - |
FormControl
Slot-based wrapper that injects ARIA attributes onto its child input element without adding an extra DOM wrapper.
agent-ready
FormDatePicker
Pre-built DatePicker field component with integrated form state.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
datePickerProps | Omit<{ selected?: Date | undefined; onSelect?: ((date: Date | undefined) => void) | undefined; placeholder?: string | undefined; dateFormat?: string | undefined; disabled?: boolean | undefined; triggerClassName?: string | undefined; calenda… /* see source */ | - | - |
FormDescription
Optional helper text displayed below the input.
agent-ready
FormField
Wraps react-hook-form's Controller and provides field context to descendants.
agent-ready
FormInput
Pre-built Input field component with integrated form state. Reduces boilerplate by combining FormField, FormItem, FormLabel, FormControl, and FormMessage.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
type | React.HTMLInputTypeAttribute | undefined | - | - | |
variant | "search" | "default" | undefined | - | - | |
inputProps | Omit<Omit<InputProps, "ref"> & React.RefAttributes<HTMLInputElement>, "type" | "variant"> | undefined | - | - |
FormItem
Layout wrapper for a form field. Generates a unique ID for accessibility linking.
agent-ready
FormLabel
Label that auto-links to the form field input via generated IDs. Applies error styling when the field has a validation error.
agent-ready
FormMessage
Displays the validation error message from react-hook-form field state. Falls back to children if no error is present. Always renders to prevent layout shift when errors appear.
agent-ready
FormRadioGroup
Pre-built RadioGroup field component with integrated form state.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
options | FormRadioOption[] | ✓ | - | - |
orientation | "horizontal" | "vertical" | undefined | - | - | |
radioGroupProps | Omit<{ orientation?: "horizontal" | "vertical" | undefined; noGap?: boolean | undefined; className?: string | undefined; } & Omit<RadioGroupProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>, "defaultV… /* see source */ | - | - |
FormSelect
Pre-built Select field component with integrated form state.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
options | FormSelectOption[] | ✓ | - | - |
selectProps | Omit<SelectSharedProps & { value?: string | undefined; defaultValue?: string | undefined; onValueChange?(value: string): void; } & { allowClear?: boolean | undefined; }, "defaultValue" | "onValueChange"> | undefined | - | - |
FormSwitch
Pre-built Switch field component with integrated form state.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
switchProps | Omit<{ size?: ComponentSize | undefined; color?: ComponentColor | undefined; radius?: BorderRadius | undefined; className?: string | undefined; thumbClassName?: string | undefined; } & Omit<SwitchProps & React.RefAttributes<HTMLButtonElemen… /* see source */ | - | - | |
layout | "row" | "column" | undefined | - | - |
FormTagInput
Pre-built TagInput field component with integrated form state. Perfect for multi-select with search and tag display.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
options | TagInputOption[] | undefined | - | - | |
allowCustomTags | boolean | undefined | - | - | |
variant | "search" | "default" | undefined | - | - | |
tagInputProps | Omit<TagInputProps & React.RefAttributes<HTMLInputElement | TagInputRef>, "label" | "value" | "placeholder" | "onTagsChange"> | undefined | - | - |
FormTextArea
Pre-built TextArea field component with integrated form state.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | undefined | - | - | |
description | string | undefined | - | - | |
placeholder | string | undefined | - | - | |
textAreaProps | (Omit<TextAreaProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>) | undefined | - | - |
Input
Text input with optional label, prefix/suffix slots, and a search variant. Forwards refs and all native <input> attributes.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
error | string | undefined | - | Validation error message. When provided, displays error styling (red border) and the message below the input. | |
label | string | undefined | - | Optional label displayed above the input | |
prefix | React.ReactNode | - | Prefix element displayed before the input (left side) | |
variant | "search" | "default" | undefined | 'default' | Variant of the input - default: Standard text input - search: Input with magnifying glass icon on the right | |
size | InputSize | undefined | 'default' | Size of the input - default: padding 10px 12px, icon 16px - medium: padding 6px 12px, icon 12px | |
wrapperClassName | string | undefined | - | Custom className for the root wrapper | |
suffix | React.ReactNode | - | Suffix element displayed after the input (right side) |
Label
Accessible text label for form controls. Associates with an input via htmlFor and supports a required-mark indicator. Built on Radix Label.
agent-ready
MultiLevelSelect
Multi-level select component with collapsible sections.
agent-ready
MultiSelect
Multi-select picker built on Radix Popover + Checkbox. Sibling to <[**Select**](/reference/ui/components/forms/#select)> for cases where consumers need to pick more than one option (filter rows, multi-target actions, tag-style inputs). The pop…
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
options | MultiSelectOption[] | ✓ | - | - |
value | string[] | undefined | - | Controlled selected values. Omit to use defaultValue for uncontrolled mode. | |
defaultValue | string[] | undefined | - | Initial values for uncontrolled mode. Ignored when value is provided. | |
onValueChange | ((next: string[]) => void) | undefined | - | - | |
placeholder | React.ReactNode | - | - | |
disabled | boolean | undefined | - | - | |
size | MultiSelectSize | undefined | - | - | |
variant | MultiSelectVariant | undefined | - | - | |
emptyMessage | React.ReactNode | - | Rendered inside the popover when options is empty. | |
maxSelectedDisplay | number | undefined | - | Max number of selected chips rendered in the trigger before collapsing the rest into a "+N more" badge. undefined (de… | |
className | string | undefined | - | - | |
contentClassName | string | undefined | - | - | |
aria-label | string | undefined | - | Accessible label - applied to the trigger button. | |
id | string | undefined | - | - | |
name | string | undefined | - | - |
Radio
Radio button component (use within RadioGroup)
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | ComponentSize | undefined | 'md' | Size variant of the radio | |
color | "success" | "warning" | "error" | "primary" | "default" | undefined | 'default' | Color variant when checked | |
radius | BorderRadius | undefined | 'full' | Border radius variant (full makes it circular) | |
className | string | undefined | - | Custom className for the root element | |
label | string | undefined | - | Label text (or use children for custom content) | |
children | React.ReactNode | - | Children content (takes precedence over label) | |
indicatorClassName | string | undefined | - | Custom className for the indicator element |
RadioCard
RadioCard component - button-like radio option
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | ComponentSize | undefined | 'md' | Size variant of the radio | |
color | "success" | "warning" | "error" | "primary" | "default" | undefined | 'default' | Color variant when checked | |
radius | BorderRadius | undefined | 'full' | Border radius variant (full makes it circular) | |
className | string | undefined | - | Custom className for the root element | |
label | string | undefined | - | Label text (or use children for custom content) | |
children | React.ReactNode | - | Children content (takes precedence over label) | |
indicatorClassName | string | undefined | - | Custom className for the indicator element |
RadioGroup
RadioGroup component - container for Radio items
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
orientation | "horizontal" | "vertical" | undefined | 'vertical' | Layout orientation | |
noGap | boolean | undefined | false | Remove gap between radio items | |
className | string | undefined | - | Custom className for the group |
Select
Dropdown select built on Radix UI. Supports default and colored variants, multiple sizes, and full keyboard navigation.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
allowClear | boolean | undefined | false | Show a clear button when a value is selected |
Switch
Switch component for toggle controls with full customization
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
size | ComponentSize | undefined | 'md' | Size variant of the switch | |
color | "success" | "warning" | "error" | "primary" | "default" | undefined | 'default' | Color variant when checked | |
radius | BorderRadius | undefined | 'none' | Border radius variant | |
className | string | undefined | - | Custom className for the root element | |
thumbClassName | string | undefined | - | Custom className for the thumb element |
TagInput
Text input that converts comma- or Enter-separated entries into removable tag chips below the field.
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
value | string[] | undefined | - | Controlled tags (array of tag values) | |
onTagsChange | ((tags: string[]) => void) | undefined | - | Callback when tags change (add/remove) | |
onInputChange | ((value: string) => void) | undefined | - | Callback when input value changes (typing). Receives current input value. Useful for async option loading or custom fil… | |
onSubmit | ((tags: string[]) => void) | undefined | - | Callback when user presses Enter (submit). Receives current tags. Called after adding a tag from selection or typed tex… | |
options | TagInputOption[] | undefined | - | Options to show in the dropdown when input is focused | |
placeholder | string | undefined | - | Placeholder when input is empty | |
disabled | boolean | undefined | - | Disabled state | |
allowCustomTags | boolean | undefined | true | Whether to allow adding custom tags by typing and pressing Enter | |
filterOptions | ((options: TagInputOption[], query: string) => TagInputOption[]) | undefined | - | Filter options by input value. Receives options and query, returns filtered options. When undefined, filters by case-in… | |
variant | "search" | "default" | undefined | 'search' | Input variant - 'search' shows magnifying glass icon | |
label | string | undefined | - | Label for the input | |
id | string | undefined | - | HTML id for the input | |
className | string | undefined | - | Custom className for the root | |
wrapperClassName | string | undefined | - | Custom className for the wrapper | |
dropdownMinHeight | string | undefined | - | Minimum height of the dropdown (CSS value, e.g. '100px', '6rem') | |
dropdownMaxHeight | string | undefined | '12rem' | Maximum height of the dropdown (CSS value, e.g. '300px', '20rem') | |
size | ComponentSize | undefined | 'lg' | Size of the tag input — matches Select sizes - sm: 24px height - md: 32px height - lg: 40px height | |
renderDropdown | ((props: TagInputDropdownProps) => React.ReactNode) | undefined | - | Render custom dropdown content. When provided, replaces the default dropdown. Use this to apply your own styling or str… |
TextArea
TextArea component with label support and error handling
agent-ready
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
error | string | undefined | - | Validation error message. When provided, displays error styling (red border) and the message below the textarea. | |
label | string | undefined | - | Optional label displayed above the textarea | |
wrapperClassName | string | undefined | - | Custom className for the root wrapper |