Cascader

Pick one option from a tree, one level at a time. Think continent, then country, then city.

Preview

Usage

import { z } from 'zod'
import { AutoForm } from '@vitnode/core/components/form/auto-form'
import { AutoFormCascader } from '@vitnode/core/components/form/fields/cascader'

const formSchema = z.object({
  office: z.string({ error: 'Pick an office to continue' }),
  backupOffice: z.string().optional(),
})
<AutoForm
  formSchema={formSchema}
  fields={[
    {
      id: 'office',
      component: (props) => (
        <AutoFormCascader
          {...props}
          label="Office"
          options={locations}
          searchable
        />
      ),
    },
  ]}
/>

The form stores the picked leaf's value ("krakow"), not the path. Optional fields get a clear button automatically.

Options

A plain tree. An option with children is a branch that opens the next level; one without is a pickable leaf.

import type { CascaderOption } from '@vitnode/core/components/ui/cascader'

const locations: CascaderOption[] = [
  {
    label: 'Europe',
    value: 'europe',
    children: [
      {
        label: 'Poland',
        value: 'poland',
        children: [
          { label: 'Warsaw', value: 'warsaw' },
          { label: 'Kraków', value: 'krakow' },
        ],
      },
      { label: 'Iceland', value: 'iceland', disabled: true },
    ],
  },
]

Need "Europe / Poland" too? onValueChange also gets the full path:

<Cascader
  onValueChange={(value, path) => setTrail(path.map((option) => option.label))}
  options={locations}
/>

searchable adds a box that searches every leaf at once. Type "krak" in the preview and "Europe / Poland / Kraków" is one click away. Accents don't matter: "sao" finds São Paulo.

Columns

By default a branch replaces the list with its children, with a back button on top. The popup stays the field's width.

layout="columns" shows each level in a new column, and the popup widens to fit. Add expandTrigger="hover" to open branches on hover. Phones always drill down: there's no room for columns at 375px.

<Cascader expandTrigger="hover" layout="columns" options={locations} />

Levels slide in from the direction you moved. The popup's height (drill) or width (columns) animates with them, mirrored in RTL. Reduced motion switches everything instantly.

Accessibility

  • Each level is a keyboard listbox: ↑ ↓ move, → (← in RTL) or Enter opens a branch, ← goes back, Home / End jump, Escape closes.
  • Branches announce whether they're open, and the picked path is marked selected.
  • Label it. AutoFormCascader does it for you; a standalone Cascader needs aria-labelledby.

Props

Prop

Type