MDK Logo

Form

Form inputs, selects, checkboxes, and form validation components

Form components for building data entry interfaces.

Prerequisites

  • Complete the installation

  • Add the dependency to your app's package.json
{
  "dependencies": {
    "@tetherto/mdk-react-devkit": "*",
    "@tetherto/mdk-react-adapter": "*",
    "@tetherto/mdk-ui-foundation": "*"
  }
}

Run npm install from the mdk/ui workspace root after your app is under apps/ so npm links workspace packages.

  • Import styles: import '@tetherto/mdk-react-devkit/styles.css'

Components

@tetherto/mdk-react-devkit

Core form workflow

import { Form, FormField } from '@tetherto/mdk-react-devkit'

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

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>
  )
}
@tetherto/mdk-react-devkit

Pre-built input field

import { FormInput } from '@tetherto/mdk-react-devkit'
@tetherto/mdk-react-devkit

Date range picker

import { DateRangePicker } from '@tetherto/mdk-react-devkit'

Single-date and range-date pickers built on react-day-picker. The range picker includes presets and a modal-style popover with Clear / Apply actions.

Data contracts

type DateRange = { from: Date | undefined; to?: Date | undefined };
type PresetItem = { label: string; value: DateRange };

Example

/**
 * Runnable example for DatePicker and DateRangePicker.
 */
import { useState } from 'react'
import type { DateRange } from '@tetherto/mdk-react-devkit'
import { DatePicker, DateRangePicker } from '@tetherto/mdk-react-devkit'

export const DatePickerExample = () => {
  const [date, setDate] = useState<Date>()
  const [range, setRange] = useState<DateRange>()

  return (
    <div className="mdk-example-row">
      <DatePicker selected={date} onSelect={setDate} />
      <DateRangePicker selected={range} onSelect={setRange} showPresets />
    </div>
  )
}
@tetherto/mdk-react-devkit

Import the public APIs on this page from @tetherto/mdk-react-devkit.

Cascader

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

Features: - Two-column layout: categories on left, options on right - Single or multiple selection modes - Search/filter functionality via TagInput - Category-level selection (select/deselect all children) - Indeterminate state for partial selections - Tag display for multiple selections - Keyboard navigation support - Disabled state support

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/cascader/index.tsx

Props

PropStatusType / OptionsDefaultDescription
optionsRequiredCascaderOption[]-Hierarchical options to display in the cascader Parent options with children appear in the left panel Child options appear in the right panel when parent is selected
classNameOptionalstring-Custom className for the root cascader element
disabledOptionalbooleanfalseDisable the entire cascader (input and all options)
dropdownClassNameOptionalstring-Custom className for the dropdown panels container
multipleOptionalbooleanfalseEnable multiple selection mode - true: Shows checkboxes, allows multiple selections, displays selected items as tags - false: Shows radio buttons, allows single selection
onChangeOptional((value: CascaderValue | CascaderValue[] | null) => void)-Callback when selection changes - For single select: receives CascaderValue or null - For multiple select: receives CascaderValue[] or null
placeholderOptionalstring"Select..."Placeholder text shown in the input when no selections are made
valueOptionalCascaderValue | CascaderValue[]-Current selected value(s) - For single select: CascaderValue (e.g., ['category', 'option']) - For multiple select: CascaderValue[] (e.g., [['cat1', 'opt1'], ['cat2', 'opt2']])

Checkbox

Checkbox component with full customization

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/checkbox/index.tsx

Props

PropStatusType / OptionsDefaultDescription
checkedOptionalCheckedState-Controlled checked state
classNameOptionalstring-Custom className for the root element
colorOptional"success" | "warning" | "error" | "primary" | "default""primary"Color variant when checked
defaultCheckedOptionalCheckedState-Uncontrolled initial checked state
disabledOptionalbooleanfalseDisable the input
indicatorClassNameOptionalstring-Custom className for the indicator element
onCheckedChangeOptional(((checked: CheckedState) => void) & ((checked: CheckedState) => void))-Callback when the checked state changes
radiusOptional"small" | "none" | "medium" | "large" | "full""none"Border radius variant
sizeOptional"sm" | "md" | "lg" | "xs""md"Size variant of the checkbox

CurrencyToggler

CurrencyToggler component for switching between currencies

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/currency-toggler/index.tsx

Props

PropStatusType / OptionsDefaultDescription
currenciesRequired(string | CurrencyItem)[]-List of currency options
onChangeRequired(currency: string) => void-Fired with the selected currency value when a button is clicked
valueRequiredstring-Currently selected currency value
classNameOptionalstring-Additional class for the root element

DatePicker

Single-date selection component built on react-day-picker with the MDK dark theme. Controlled via selected / onSelect

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/date-picker/index.tsx

Props

PropStatusType / OptionsDefaultDescription
calendarClassNameOptionalstring-Custom className for the calendar
dateFormatOptionalstring"MM/dd/yyyy"Date format for display
disabledOptional(boolean & (Matcher | Matcher[]))falseWhether the picker is disabled
onSelectOptional((date: Date | undefined) => void)-Callback when date changes
placeholderOptionalstring"Pick a date"Placeholder text when no date is selected
selectedOptionalDate-Currently selected date
triggerClassNameOptionalstring-Custom className for the trigger button

DateRangePicker

Date-range selection component with preset shortcuts (last 7/14/30/90 days) and a modal interface. Controlled via selected / onSelect

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/date-picker/index.tsx

Props

PropStatusType / OptionsDefaultDescription
allowFutureDatesOptionalbooleanfalseWhether to allow future dates
calendarClassNameOptionalstring-Custom className for the calendar
dateFormatOptionalstring"MM/dd/yyyy"Date format for display
disabledOptional(boolean & (Matcher | Matcher[]))falseWhether the picker is disabled
modalClassNameOptionalstring-Custom className for the modal
onSelectOptional((range: DateRange | undefined) => void)-Callback when date range changes
placeholderOptionalstring"Pick a date range"Placeholder text when no range is selected
presetsOptionalPresetItem[]-Custom preset items
selectedOptionalDateRange-Selected date range
showPresetsOptionalbooleantrueWhether to show preset buttons
triggerClassNameOptionalstring-Custom className for the trigger button

Form

React Hook Form provider wrapper. Pass the result of useForm() as form and render fields via FormField / FormItem / FormLabel / FormControl / FormMessage

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/index.tsx

Props

PropStatusType / OptionsDefaultDescription
childrenRequiredReact.ReactNode--
formRequiredUseFormReturn<TFieldValues>--

FormCascader

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

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
optionsRequiredCascaderOption[]--
cascaderPropsOptionalOmit<CascaderProps & React.RefAttributes<HTMLDivElement>, "onChange" | "value" | "options" | "placeholder">--
descriptionOptionalstring--
labelOptionalstring--
multipleOptionalboolean--
placeholderOptionalstring--

FormCheckbox

Pre-built Checkbox field component with integrated form state

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
checkboxPropsOptional({ checked?: CheckedState | undefined; defaultChecked?: CheckedState | undefined; disabled?: boolean | undefined; size?: CheckboxSize | undefined; color?: ComponentColor | undefined; radius?: BorderRadius | undefined; className?: string | u… /* see source */--
descriptionOptionalstring--
labelOptionalstring--
layoutOptional"row" | "column"--
placeholderOptionalstring--

FormControl

Slot-based wrapper that injects ARIA attributes onto its child input element without adding an extra DOM wrapper

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/index.tsx

FormDatePicker

Pre-built DatePicker field component with integrated form state

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
datePickerPropsOptionalobject--
descriptionOptionalstring--
labelOptionalstring--
placeholderOptionalstring--

FormDescription

Optional helper text displayed below the input

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/index.tsx

FormField

Wraps react-hook-form's Controller and provides field context to descendants

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/index.tsx

FormInput

Pre-built Input field component with integrated form state. Reduces boilerplate by combining FormField, FormItem, FormLabel, FormControl, and FormMessage

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
descriptionOptionalstring--
inputPropsOptionalOmit<Omit<InputProps, "ref"> & React.RefAttributes<HTMLInputElement>, "type" | "variant">--
labelOptionalstring--
placeholderOptionalstring--
typeOptionalReact.HTMLInputTypeAttribute--
variantOptional"search" | "default"--

FormItem

Layout wrapper for a form field. Generates a unique ID for accessibility linking

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/index.tsx

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

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/index.tsx

Props

PropStatusType / OptionsDefaultDescription
htmlForOptionalstring-Id of the input being labelled

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

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/index.tsx

FormRadioGroup

Pre-built RadioGroup field component with integrated form state

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
optionsRequiredFormRadioOption[]--
descriptionOptionalstring--
labelOptionalstring--
orientationOptional"horizontal" | "vertical"--
placeholderOptionalstring--
radioGroupPropsOptionalobject--

FormSelect

Pre-built Select field component with integrated form state

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
optionsRequiredFormSelectOption[]--
descriptionOptionalstring--
labelOptionalstring--
placeholderOptionalstring--
selectPropsOptionalobject--

FormSwitch

Pre-built Switch field component with integrated form state

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
descriptionOptionalstring--
labelOptionalstring--
layoutOptional"row" | "column"--
placeholderOptionalstring--
switchPropsOptionalobject--

FormTagInput

Pre-built TagInput field component with integrated form state. Perfect for multi-select with search and tag display

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
allowCustomTagsOptionalboolean--
descriptionOptionalstring--
labelOptionalstring--
optionsOptionalTagInputOption[]--
placeholderOptionalstring--
tagInputPropsOptionalobject--
variantOptional"search" | "default"--

FormTextArea

Pre-built TextArea field component with integrated form state

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/form/form-fields.tsx

Props

PropStatusType / OptionsDefaultDescription
descriptionOptionalstring--
labelOptionalstring--
placeholderOptionalstring--
textAreaPropsOptional(Omit<TextAreaProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>)--

Input

Text input with optional label, prefix/suffix slots, and a search variant. Forwards refs and all native <input> attributes

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/input/index.tsx

Props

PropStatusType / OptionsDefaultDescription
errorOptionalstring-Validation error message. When provided, displays error styling (red border) and the message below the input
idOptionalstringauto-generatedHTML id for the input. Required when using label for accessibility
labelOptionalstring-Optional label displayed above the input
prefixOptionalReact.ReactNode-Prefix element displayed before the input (left side)
sizeOptional"default" | "medium""default"Size of the input - default: padding 10px 12px, icon 16px - medium: padding 6px 12px, icon 12px
suffixOptionalReact.ReactNode-Suffix element displayed after the input (right side)
variantOptional"search" | "default""default"Variant of the input - default: Standard text input - search: Input with magnifying glass icon on the right
wrapperClassNameOptionalstring-Custom className for the root wrapper

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

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/label/index.tsx

Props

PropStatusType / OptionsDefaultDescription
htmlForOptionalstring-Id of the input being labelled

MultiLevelSelect

Multi-level select component with collapsible sections

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/multi-level-select/index.tsx

MultiSelect

Multi-select picker built on Radix Popover + Checkbox. Sibling to <Select> for cases where consumers need to pick more than one option (filter rows, multi-target actions, tag-style inputs). The popover stays open on toggle; Esc / outside-click closes it. Selected values render as removable chips in the trigger, with an optional "clear all" affordance and a +N more overflow chip via maxSelectedDisplay.

Controlled vs uncontrolled is decided by the presence of value (mirrors Radix Select's convention): pass value for controlled, defaultValue for uncontrolled

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/multi-select/index.tsx

Props

PropStatusType / OptionsDefaultDescription
optionsRequiredMultiSelectOption[]-{ value, label, disabled? } entries to render as option rows
aria-labelOptionalstring-Accessible label - applied to the trigger button
classNameOptionalstring-Extra class on the trigger button
contentClassNameOptionalstring-Extra class on the popover content
defaultValueOptionalstring[][]Initial values for uncontrolled mode. Ignored when value is provided
disabledOptionalbooleanfalseDisables the trigger (popover does not open)
emptyMessageOptionalReact.ReactNode"No options"Rendered inside the popover when options is empty
idOptionalstring--
maxSelectedDisplayOptionalnumber-Max number of selected chips rendered in the trigger before collapsing the rest into a "+N more" badge. undefined (default) renders every chip
nameOptionalstring--
onValueChangeOptional((next: string[]) => void)-Fires with the next array on toggle / chip remove / clear-all
placeholderOptionalReact.ReactNode"Select..."Rendered when nothing is selected
sizeOptional"sm" | "md" | "lg""lg"Trigger sizing tokens. Mirror the <Select> sizes
valueOptionalstring[]-Controlled selected values. Omit to use defaultValue for uncontrolled mode
variantOptional"default" | "colored""default"'colored' paints the trigger in the primary tint (matches <Select>'s colored variant)

Radio

Radio button component (use within RadioGroup)

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/radio/index.tsx

Props

PropStatusType / OptionsDefaultDescription
valueRequiredstring-Value associated with this option
childrenOptionalReact.ReactNode-Children content (takes precedence over label)
classNameOptionalstring-Custom className for the root element
colorOptional"success" | "warning" | "error" | "primary" | "default""primary"Color variant when checked
indicatorClassNameOptionalstring-Custom className for the indicator element
labelOptionalstring-Label text (or use children for custom content)
radiusOptional"small" | "none" | "medium" | "large" | "full""full"Border radius variant (full makes it circular)
sizeOptional"sm" | "md" | "lg""md"Size variant of the radio

RadioCard

RadioCard component - button-like radio option

Supports an onChange callback when selected

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/radio/index.tsx

Props

PropStatusType / OptionsDefaultDescription
valueRequiredstring-Value associated with this option
childrenOptionalReact.ReactNode-Children content (takes precedence over label)
classNameOptionalstring-Custom className for the root element
colorOptional"success" | "warning" | "error" | "primary" | "default""primary"Color variant when checked
indicatorClassNameOptionalstring-Custom className for the indicator element
labelOptionalstring-Label text (or use children for custom content)
radiusOptional"small" | "none" | "medium" | "large" | "full""full"Border radius variant (full makes it circular)
sizeOptional"sm" | "md" | "lg""md"Size variant of the radio

RadioGroup

RadioGroup component - container for Radio items

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/radio/index.tsx

Props

PropStatusType / OptionsDefaultDescription
classNameOptionalstring-Custom className for the group
noGapOptionalbooleanfalseRemove gap between radio items
orientationOptional"horizontal" | "vertical""vertical"Layout orientation

Select

Dropdown select built on Radix UI. Supports default and colored variants, multiple sizes, and full keyboard navigation

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/select/index.tsx

Props

PropStatusType / OptionsDefaultDescription
allowClearOptionalbooleanfalseShow a clear button when a value is selected
defaultValueOptionalstring-Uncontrolled initial value
onValueChangeOptional((value: string) => void)-Setter for the value
valueOptionalstring-Controlled value

Switch

Switch component for toggle controls with full customization

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/switch/index.tsx

Props

PropStatusType / OptionsDefaultDescription
checkedOptionalboolean-Controlled checked state
classNameOptionalstring-Custom className for the root element
colorOptional"success" | "warning" | "error" | "primary" | "default""default"Color variant when checked
defaultCheckedOptionalboolean-Uncontrolled initial checked state
disabledOptionalbooleanfalseDisable the switch
onCheckedChangeOptional((checked: boolean) => void)-Change handler
radiusOptional"small" | "none" | "medium" | "large" | "full""none"Border radius variant
sizeOptional"sm" | "md" | "lg""md"Size variant of the switch
thumbClassNameOptionalstring-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

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/tag-input/index.tsx

Props

PropStatusType / OptionsDefaultDescription
allowCustomTagsOptionalbooleantrueWhether to allow adding custom tags by typing and pressing Enter
classNameOptionalstring-Additional class for the inner <input>
disabledOptionalbooleanfalseDisabled state
dropdownMaxHeightOptionalstring"12rem"Maximum height of the dropdown (CSS value, e.g. '300px', '20rem')
dropdownMinHeightOptionalstring-Minimum height of the dropdown (CSS value, e.g. '100px', '6rem')
filterOptionsOptional((options: TagInputOption[], query: string) => TagInputOption[])case-insensitive includesFilter options by input value. Receives options and query, returns filtered options. When undefined, filters by case-insensitive includes
idOptionalstringauto-generatedHTML id for the input
labelOptionalstring-Label for the input
onInputChangeOptional((value: string) => void)-Callback when input value changes (typing). Receives current input value. Useful for async option loading or custom filtering
onSubmitOptional((tags: string[]) => void)-Callback when user presses Enter (submit). Receives current tags. Called after adding a tag from selection or typed text, if applicable
onTagsChangeOptional((tags: string[]) => void)-Callback when tags change (add/remove)
optionsOptionalTagInputOption[][]Options to show in the dropdown when input is focused
placeholderOptionalstring"Search..."Placeholder when input is empty
renderDropdownOptional((props: TagInputDropdownProps) => React.ReactNode)-Render custom dropdown content. When provided, replaces the default dropdown. Use this to apply your own styling or structure
sizeOptional"sm" | "md" | "lg""lg"Size of the tag input — matches Select sizes - sm: 24px height - md: 32px height - lg: 40px height
valueOptionalstring[][]Controlled tags (array of tag values)
variantOptional"search" | "default""search"Input variant; 'search' shows a magnifying-glass icon that doubles as a clear-all button
wrapperClassNameOptionalstring-Custom className for the wrapper

TextArea

TextArea component with label support and error handling

agent-ready

Source

https://github.com/tetherto/mdk/blob/main/ui/packages/react-devkit/src/primitives/components/textarea/index.tsx

Props

PropStatusType / OptionsDefaultDescription
errorOptionalstring-Validation error message. When provided, displays error styling (red border) and the message below the textarea
idOptionalstringauto-generatedHTML id for the textarea. Required when using label for accessibility
labelOptionalstring-Optional label displayed above the textarea
wrapperClassNameOptionalstring-Custom className for the root wrapper

On this page