MDK Logo
ReferenceUIComponents

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 provides FormProvider context.
  • FormField — wraps react-hook-form's Controller and 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 in form-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>
  )
}

Cascader

Two-panel hierarchical selector for picking a leaf value from a nested tree (categories → subcategories → leaf).

agent-ready

Props

PropTypeRequiredDefaultDescription
optionsCascaderOption[]-Hierarchical options to display in the cascader Parent options with children appear in the left panel Child options app…
valueCascaderValue | 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…
multipleboolean | undefinedfalseEnable multiple selection mode - true: Shows checkboxes, allows multiple selections, displays selected items as tags -…
placeholderstring | undefined'Select...'Placeholder text shown in the input when no selections are made
disabledboolean | undefinedfalseDisable the entire cascader (input and all options)
classNamestring | undefined-Custom className for the root cascader element
dropdownClassNamestring | undefined-Custom className for the dropdown panels container

Checkbox

Checkbox component with full customization

agent-ready

Props

PropTypeRequiredDefaultDescription
sizeCheckboxSize | undefined'md'Size variant of the checkbox
color"success" | "warning" | "error" | "primary" | "default" | undefined'primary'Color variant when checked
radiusBorderRadius | undefined'none'Border radius variant
classNamestring | undefined-Custom className for the root element
indicatorClassNamestring | 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

PropTypeRequiredDefaultDescription
valuestring--
classNamestring | 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

PropTypeRequiredDefaultDescription
selectedDate | undefined-Currently selected date
onSelect((date: Date | undefined) => void) | undefined-Callback when date changes
placeholderstring | undefined"Pick a date"Placeholder text when no date is selected
dateFormatstring | undefined"MM/dd/yyyy"Date format for display
disabled(boolean & (Matcher | Matcher[])) | undefinedfalseWhether the picker is disabled
triggerClassNamestring | undefined-Custom className for the trigger button
calendarClassNamestring | 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

PropTypeRequiredDefaultDescription
selectedDateRange | undefined-Selected date range
onSelect((range: DateRange | undefined) => void) | undefined-Callback when date range changes
placeholderstring | undefined"Pick a date range"Placeholder text when no range is selected
dateFormatstring | undefined"MM/dd/yyyy"Date format for display
disabled(boolean & (Matcher | Matcher[])) | undefinedfalseWhether the picker is disabled
showPresetsboolean | undefinedtrueWhether to show preset buttons
presetsPresetItem[] | undefined-Custom preset items
allowFutureDatesboolean | undefinedfalseWhether to allow future dates
triggerClassNamestring | undefined-Custom className for the trigger button
calendarClassNamestring | undefined-Custom className for the calendar
modalClassNamestring | 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

PropTypeRequiredDefaultDescription
formUseFormReturn<TFieldValues>--
childrenReact.ReactNode--

FormCascader

Pre-built Cascader field component with integrated form state. Perfect for hierarchical selections like categories and subcategories.

agent-ready

Props

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | undefined--
optionsCascaderOption[]--
multipleboolean | undefined--
cascaderPropsOmit<CascaderProps & React.RefAttributes<HTMLDivElement>, "onChange" | "value" | "options" | "placeholder"> | undefined--

FormCheckbox

Pre-built Checkbox field component with integrated form state.

agent-ready

Props

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | 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

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | undefined--
datePickerPropsOmit<{ 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

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | undefined--
typeReact.HTMLInputTypeAttribute | undefined--
variant"search" | "default" | undefined--
inputPropsOmit<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

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | undefined--
optionsFormRadioOption[]--
orientation"horizontal" | "vertical" | undefined--
radioGroupPropsOmit<{ 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

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | undefined--
optionsFormSelectOption[]--
selectPropsOmit<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

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | undefined--
switchPropsOmit<{ 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

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | undefined--
optionsTagInputOption[] | undefined--
allowCustomTagsboolean | undefined--
variant"search" | "default" | undefined--
tagInputPropsOmit<TagInputProps & React.RefAttributes<HTMLInputElement | TagInputRef>, "label" | "value" | "placeholder" | "onTagsChange"> | undefined--

FormTextArea

Pre-built TextArea field component with integrated form state.

agent-ready

Props

PropTypeRequiredDefaultDescription
labelstring | undefined--
descriptionstring | undefined--
placeholderstring | 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 &lt;input&gt; attributes.

agent-ready

Props

PropTypeRequiredDefaultDescription
errorstring | undefined-Validation error message. When provided, displays error styling (red border) and the message below the input.
labelstring | undefined-Optional label displayed above the input
prefixReact.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
sizeInputSize | undefined'default'Size of the input - default: padding 10px 12px, icon 16px - medium: padding 6px 12px, icon 12px
wrapperClassNamestring | undefined-Custom className for the root wrapper
suffixReact.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 &lt;[**Select**](/reference/ui/components/forms/#select)&gt; for cases where consumers need to pick more than one option (filter rows, multi-target actions, tag-style inputs). The pop…

agent-ready

Props

PropTypeRequiredDefaultDescription
optionsMultiSelectOption[]--
valuestring[] | undefined-Controlled selected values. Omit to use defaultValue for uncontrolled mode.
defaultValuestring[] | undefined-Initial values for uncontrolled mode. Ignored when value is provided.
onValueChange((next: string[]) => void) | undefined--
placeholderReact.ReactNode--
disabledboolean | undefined--
sizeMultiSelectSize | undefined--
variantMultiSelectVariant | undefined--
emptyMessageReact.ReactNode-Rendered inside the popover when options is empty.
maxSelectedDisplaynumber | undefined-Max number of selected chips rendered in the trigger before collapsing the rest into a "+N more" badge. undefined (de…
classNamestring | undefined--
contentClassNamestring | undefined--
aria-labelstring | undefined-Accessible label - applied to the trigger button.
idstring | undefined--
namestring | undefined--

Radio

Radio button component (use within RadioGroup)

agent-ready

Props

PropTypeRequiredDefaultDescription
sizeComponentSize | undefined'md'Size variant of the radio
color"success" | "warning" | "error" | "primary" | "default" | undefined'default'Color variant when checked
radiusBorderRadius | undefined'full'Border radius variant (full makes it circular)
classNamestring | undefined-Custom className for the root element
labelstring | undefined-Label text (or use children for custom content)
childrenReact.ReactNode-Children content (takes precedence over label)
indicatorClassNamestring | undefined-Custom className for the indicator element

RadioCard

RadioCard component - button-like radio option

agent-ready

Props

PropTypeRequiredDefaultDescription
sizeComponentSize | undefined'md'Size variant of the radio
color"success" | "warning" | "error" | "primary" | "default" | undefined'default'Color variant when checked
radiusBorderRadius | undefined'full'Border radius variant (full makes it circular)
classNamestring | undefined-Custom className for the root element
labelstring | undefined-Label text (or use children for custom content)
childrenReact.ReactNode-Children content (takes precedence over label)
indicatorClassNamestring | undefined-Custom className for the indicator element

RadioGroup

RadioGroup component - container for Radio items

agent-ready

Props

PropTypeRequiredDefaultDescription
orientation"horizontal" | "vertical" | undefined'vertical'Layout orientation
noGapboolean | undefinedfalseRemove gap between radio items
classNamestring | 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

PropTypeRequiredDefaultDescription
allowClearboolean | undefinedfalseShow a clear button when a value is selected

Switch

Switch component for toggle controls with full customization

agent-ready

Props

PropTypeRequiredDefaultDescription
sizeComponentSize | undefined'md'Size variant of the switch
color"success" | "warning" | "error" | "primary" | "default" | undefined'default'Color variant when checked
radiusBorderRadius | undefined'none'Border radius variant
classNamestring | undefined-Custom className for the root element
thumbClassNamestring | 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

PropTypeRequiredDefaultDescription
valuestring[] | 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…
optionsTagInputOption[] | undefined-Options to show in the dropdown when input is focused
placeholderstring | undefined-Placeholder when input is empty
disabledboolean | undefined-Disabled state
allowCustomTagsboolean | undefinedtrueWhether 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
labelstring | undefined-Label for the input
idstring | undefined-HTML id for the input
classNamestring | undefined-Custom className for the root
wrapperClassNamestring | undefined-Custom className for the wrapper
dropdownMinHeightstring | undefined-Minimum height of the dropdown (CSS value, e.g. '100px', '6rem')
dropdownMaxHeightstring | undefined'12rem'Maximum height of the dropdown (CSS value, e.g. '300px', '20rem')
sizeComponentSize | 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

PropTypeRequiredDefaultDescription
errorstring | undefined-Validation error message. When provided, displays error styling (red border) and the message below the textarea.
labelstring | undefined-Optional label displayed above the textarea
wrapperClassNamestring | undefined-Custom className for the root wrapper

On this page