Built on Vercel’s UI SDK 0.1.0-beta.1. Its API may change.
Tree
A tree view on Vercel's UI SDK for files and nested pages, with file paths, checkboxes, links and children that load on demand.
- Data display components
- 7 parts
- 12 examples
@tabler/icons-react@ui-sdk/core@ui-sdk/reactclass-variance-authority
pnpm dlx shadcn@latest add https://hextaui.com/r/ui-sdk-tree.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @ui-sdk/react@0.1.0-beta.1 @ui-sdk/core@0.1.0-beta.1 @tabler/icons-react class-variance-authority cnCopy and paste the following code into your project.
components/ui/ui-sdk-tree.tsx Update the import paths to match your project setup.
UI SDK adds a little CSS of its own in a cascade layer named ui-sdk. Declare that layer at the top of your global stylesheet, above the Tailwind import, so your classes win over it.
An item with a TreeGroup inside it is a branch. Give every item a unique value and the tree an accessible name. Focus stays on the item, and its label is the row you see, so selected, current and focused styles all land on the label.
Pass items and no children, and the tree renders styled rows with chevrons for you. Each item has a value, a label and optional children.
Pass paths for a file explorer, with folders first. With activation="automatic" the arrow keys select, and an onAction that returns a promise marks the row pending until it settles.
With mode="multiple", Cmd or Ctrl-click toggles an item and Shift extends a range. expandOnPress={false} leaves expanding to the chevron and the arrow keys.
Add checkable and a TreeItemCheckbox in each label. Checking a branch checks everything in it, and a partly checked branch shows a dash.
Items with an href render as links. With mode="none" and current, the current page gets aria-current, its parents open and it takes the tab stop.
Mark an item branch before its children exist, and loadChildren runs the first time it opens. The chevron turns into a spinner while it loads, and into a retry icon if it fails. Archive fails once.
variant="lines" draws an indent guide for each open group, and size="sm" makes the rows shorter.
A controller from createTreeController() expands, collapses, selects and reveals items from anywhere.
With hiddenUntilFound, closed groups stay in the page, so the browser’s Find in Page can match Phobos and open Mars to show it.
A disabled item can still take focus, so screen readers find it, but it can’t be selected, checked or opened.
Rows indent from the right, the chevron points left, and the Left and Right arrow keys swap.
| Key | Action |
|---|---|
| ↓↑ | Moves to the next or previous visible item. |
| → | Opens a branch, or moves to its first child. |
| ← | Closes a branch, or moves to its parent. |
| HomeEnd | Moves to the first or last visible item. |
| Alt→ | Opens a branch and everything inside it. |
| * | Opens every branch beside the focused one. |
| Enter | Selects the item and runs its action, or follows its link. |
| Space | Checks the item when the tree is checkable, otherwise selects it. |
| Shift↓ | Extends a multiple selection. |
| ⌘A | Selects every visible item in multiple mode. |
The tree follows the WAI-ARIA tree view pattern with one tab stop. Tab lands on the current page, the selected item or the first item. Typing a letter moves to the next item that starts with it. While a slow onAction runs, screen readers hear pendingAnnouncement after a second, so set it in your page’s language.
Groups open and close by height only when motion is allowed. On touch screens rows are taller, and in forced colors mode the selected and current rows get an outline.
Each part wraps the UI SDK part of the same name and accepts all of its props, including render and a className that can be a function of the part’s state.
| Prop | Type | Default |
|---|---|---|
itemsThe whole hierarchy. Without children, the tree renders styled rows from it. | TreeItemData[] | – |
pathsFile paths. Folders become branches; a path ending in / is an empty folder. | string[] | – |
mode | "single" | "multiple" | "none" | "single" |
value | string | string[] | null | – |
defaultValue | string | string[] | null | – |
onValueChange | (value, details) => void | – |
activation | "automatic" | "manual" | "manual" |
expanded | string[] | – |
defaultExpanded | string[] | – |
onExpandedChange | (expanded, details) => void | – |
expandOnPress | boolean | true |
checkable | boolean | false |
checked | string[] | – |
defaultChecked | string[] | – |
onCheckedChange | (checked, details) => void | – |
checkStrategy | "leaf" | "trunk" | "branch" | "independent" | "leaf" |
onActionRuns on press or Enter. Return a promise to mark the item pending. | (value, details) => unknown | – |
pendingAnnouncement | string | – |
loadChildren | (value, { signal }) => Promise<unknown> | – |
current | string | null | – |
disabled | boolean | false |
hiddenUntilFound | boolean | false |
keepMounted | boolean | false |
variant | "default" | "lines" | "default" |
size | "default" | "sm" | "default" |
controllerFrom createTreeController(). | TreeController | – |
| Attribute | Description |
|---|---|
data-slot="tree" | Target the tree in CSS. |
data-variant | The variant: default or lines. |
data-size | The size: default or sm. |
--tree-row-height | The height of each row, set by size. |
--tree-indent | How far each level indents. |
| Prop | Type | Default |
|---|---|---|
valueUnique in the tree. | string | – |
branchSet it for a branch whose children load later. | boolean | – |
disabled | boolean | false |
labelThe text typeahead matches, when the label isn’t plain text. | string | – |
render | ReactElement | (props, state) => ReactElement | – |
| Attribute | Description |
|---|---|
data-slot="tree-item" | Target an item in CSS. It holds focus. |
data-level | The depth, from 1. |
data-branch | Present on a branch. |
data-expanded | Present while a branch is open. |
--tree-level | The depth, for indenting a flat list. |
| Prop | Type | Default |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | – |
| Attribute | Description |
|---|---|
data-slot="tree-label" | Target a row in CSS. |
data-selected | Present while the item is selected. |
data-current | Present on the current page’s item. |
data-expanded | Present while a branch is open. |
data-pending | Present while the item’s onAction runs. |
data-disabled | Present when the item is disabled. |
| Prop | Type | Default |
|---|---|---|
childrenDefaults to a chevron, a spinner while loading and a retry icon after a failure. | ReactNode | (state) => ReactNode | – |
| Attribute | Description |
|---|---|
data-slot="tree-indicator" | Target the chevron in CSS. |
data-loading | Present while children load. |
data-failed | Present after children failed to load. |
| Prop | Type | Default |
|---|---|---|
childrenDefaults to a check, or a dash when mixed. | ReactNode | (state) => ReactNode | – |
| Attribute | Description |
|---|---|
data-slot="tree-checkbox" | Target the checkbox in CSS. |
data-checked | Present while checked. |
data-indeterminate | Present while a branch is partly checked. |
| Prop | Type | Default |
|---|---|---|
keepMounted | boolean | – |
hiddenUntilFound | boolean | – |
| Attribute | Description |
|---|---|
data-slot="tree-group" | Target a group in CSS. |
data-open | Present while open. |
--tree-group-height | The group’s height while it animates. |
- AvatarUser photos with an initials fallback, status badges and stacked groups that collapse into a count.
- BadgeStatus labels with colored dots, removable tags that slide closed and counts that roll to their new value.
- CardA surface for grouping content, with three variants, edge-to-edge media, concentric radii and whole-card links.
- ChartRecharts charts with themed colors, a tooltip and legend that read labels from one config, and keyboard navigation with a visible focus ring.
- Data tableA table for real data, with sorting, search, row selection, pinned columns, a sticky header and pagination.
- ItemA row of media, text and actions for lists, settings and pickers, with a grouped surface and a hover highlight that glides between rows.