Skip to content

Tree Select

Hierarchical multi-select with checkbox cascading, mixed (partial) parent state, recursive search that auto-expands matched ancestors, and tag overflow.

Forms & Inputs·Available inReactVueAngular·View as Markdown

Preview

tsx

Switch the framework picker (top-right of the panel) to render the same demo live in React, Vue, or Angular — same class names, ARIA, and visual output across all three.

Installation

Sisyphos UI ships unified packages for React, Vue, and Angular. Pick the one that matches your stack — every framework exports the same component classes, ARIA semantics, and CSS tokens.

$ pnpm add @sisyphos-ui/react

Then import the bundled stylesheet once at app entry: import "@sisyphos-ui/react/styles.css";

Usage

Idiomatic usage in each supported framework
import { useState } from "react";
import { TreeSelect } from "@sisyphos-ui/react";

const tree = [
  { id: "1", label: "Engineering", children: [
    { id: "1-1", label: "Web" },
    { id: "1-2", label: "Mobile" },
  ]},
  { id: "2", label: "Design" },
];

export const Departments = () => {
  const [ids, setIds] = useState<string[]>([]);
  return <TreeSelect label="Departments" data={tree} value={ids} onChange={setIds} />;
};

Searchable

Add `searchable` and `clearable` for dense trees.

tsx

Multi select

Pre-fill a selection via `value` — renders compact chip summary with `+N` overflow.

tsx

Error state

Inline validation mirrors the other form controls.

tsx
Pick at least one team to route this request.

API

PropTypeDefaultDescription
nodes*TreeNode[]Hierarchical data with `id`, `label`, optional `children` and `disabled`.
valueTreeNodeId[]Controlled selected ids.
defaultValueTreeNodeId[]Initial uncontrolled selection.
onChange(ids: TreeNodeId[]) => voidCalled with the next selection.
labelstringField label rendered above the trigger.
placeholderstringTrigger placeholder when nothing is selected.
triggerLabelstringOverride for the trigger's primary text.
searchablebooleantrueShow a search input above the tree. Auto-expands matched ancestors while a term is active.
searchPlaceholderstring"Search…"Placeholder for the search input.
cascadebooleantrueToggle a parent node to also toggle its descendants. With `false`, only the node itself is selected.
maxTagCountnumber3Show up to this many tags in the trigger; remaining count collapses into `+N`.
clearablebooleanfalseRender a `Clear all` button when there is a selection.
fullWidthbooleanfalseStretch the trigger to its container.
size"sm" | "md" | "lg""md"Field height + typography scale.
placementPlacement"bottom-start"Initial popover placement (auto-flips when needed).
errorbooleanfalseMarks the field as invalid for styling and ARIA.
errorMessagestringMessage shown below the field when `error` is true.
disabledbooleanfalseDisables interaction.
requiredbooleanfalseAdds the required indicator and ARIA flag.

The full API including refs, ARIA attributes, and HTML passthroughs lives in the package README on npm.

Accessibility

  • Each row is a role="checkbox" with aria-checked set to "true", "false", or "mixed" for partial parents.
  • The dropdown uses role="tree"; expand chevrons expose aria-expanded.
  • Trigger is wired with role="combobox" + aria-expanded and aria-haspopup="tree".
  • Search input is portal-mounted alongside the tree and receives focus on open.

Keyboard interactions

KeyAction
TabMoves focus to and inside the picker.
EnterthenSpaceToggles the focused node.
EscCloses the popover.
Need more?View on npm →
Was this page helpful?