Tree View

A hierarchical tree for scene graphs, file trees, and outlines. You supply a flat array of TreeDataItem nodes (each pointing at its parentId); the useTreeState hook derives the visible rows — with indent and guideline metadata — and manages expand-collapse state. Icons and label rendering are left to the caller. For trees with thousands of nodes, swap TreeView for VirtualTreeView — it shares the same props plus a height.

Basic

Pass the visibleData from useTreeState to data, and wire expandedItems, onToggleItem, and hasDescendants so collapsible folders get a chevron. getIcon returns whatever node icon you want, with the expanded flag for folder-open states.

src
components
Button.tsx
Input.tsx
hooks
useTree.ts
index.ts
README.md

Selectable

Set isSelectable and control selection with selectedItemIds / onSelectionChange. With the default selectionMode="multi", Cmd/Ctrl-click toggles individual rows and Shift-click selects a range; selecting a parent implicitly covers its descendants.

Scene
Lights
KeyLight
FillLight
Meshes
Robot
Ground
Camera

Selected: robot

Searchable

TreeSearchBar is a controlled input with case-sensitive and regex toggles. Feed its state into useTreeSearch, which returns the filteredData (matches plus their ancestor paths) and a renderLabel that highlights the matched substring. Pass filteredData back through useTreeState and hand renderLabel to the TreeView.

app
routes
home.tsx
about.tsx
settings.tsx
lib
fetcher.ts
format.ts
config.ts

Quiet rows

Three opt-outs tune the tree for dense sidebars (the Dream Studio repos list uses all three). chevronPosition="trailing" moves a smaller, dimmed expand chevron to sit right after the label text — collapsed it points left, toward the label it reveals under. hoverSubtree={false} limits the hover wash to the row under the cursor instead of highlighting the whole subtree as one block. loneSelectionStyle="ring" draws a lone selected row with the same accent ring group selections use, leaving the row background transparent instead of the solid fill. A fourth, groupSelection="row", changes what selecting a group MEANS: only the clicked row is marked — descendants are untouched, and a selected group renders like any lone selection instead of a ring around its whole subtree.

studio
main
panel-integrations
uikit
docs-restructure

Props

TreeView / VirtualTreeView

PropTypeDefaultDescription
dataTreeDataItemWithMeta<T>[]Flattened rows with metadata — pass visibleData from useTreeState.
getIcon(item: T, expanded?: boolean) => ReactNodeIcon for each node. Receives the expanded flag for folder-open states.
expandedItemsSet<string>IDs of expanded collapsible nodes.
onToggleItem(id: string) => voidCalled when a chevron is clicked.
onItemHover(id: string | null) => voidCalled on row mouse enter / leave.
hoveredIdstring | nullControlled hovered row id.
isSelectablebooleanfalseEnables row selection.
selectedItemIdsSet<string>Controlled set of selected node ids.
onSelectionChange(ids: Set<string>) => voidCalled when the selection changes.
selectionMode'single' | 'multi''multi'multi enables Cmd/Ctrl-click toggle and Shift-click range.
hideExpandbooleanfalseHide expand chevrons entirely.
hasDescendants(id: string) => boolean() => falseWhether a node has children — pass the helper from useTreeState.
renderLabel(label: string, itemId: string) => ReactNodeidentityCustom label rendering — pass renderLabel from useTreeSearch for highlights.
renderContextMenu(item: T) => ReactNodeRight-click menu content for a row.
hoverSubtreebooleantrueHovering a group also highlights its whole subtree as one block. Set false for row-only hover.
loneSelectionStyle'fill' | 'ring''fill'Lone selected row: solid fill, or the accent ring group selections use (transparent background).
chevronPosition'leading' | 'trailing''leading'trailing renders a smaller, dimmed chevron after the label text; collapsed points left.
groupSelection'subtree' | 'row''subtree''row' = selecting a group marks only that row; descendants stay unmarked.
classNamestringExtra classes on the container.
heightnumber | string'100%'VirtualTreeView only — container height for virtualization.
overscannumber5VirtualTreeView only — extra rows rendered outside the viewport.

TreeDataItem

FieldTypeDescription
idstringUnique node identifier.
parentIdstring | nullParent id, or null for roots.
labelstringDisplay text (also the search target).
isCollapsiblebooleanMarks a node as an expandable folder.
actionsReactNodeTrailing action content shown on the row.
disablebooleanDim and disable interaction for the row.
selectablebooleanSet false to exclude the row from selection.

TreeSearchBar

PropTypeDescription
searchQuerystringCurrent query text.
setSearchQuery(query: string) => voidUpdates the query.
isCaseSensitivebooleanCase-sensitive toggle state.
setIsCaseSensitive(value: boolean | ((prev: boolean) => boolean)) => voidToggles case sensitivity.
isRegexbooleanRegex toggle state.
setIsRegex(value: boolean | ((prev: boolean) => boolean)) => voidToggles regex mode.
isRegexValidbooleanWhether the current regex compiles — from useTreeSearch.
searchResultsCountnumberNumber of direct matches — from useTreeSearch.
classNamestringExtra classes on the container.

useTreeState({ data, defaultExpanded?, expandedItems?, onToggleItem? })

ReturnsTypeDescription
visibleDataTreeDataItemWithMeta<T>[]Flattened, metadata-tagged rows with collapsed subtrees hidden — pass to data.
dataWithMetaTreeDataItemWithMeta<T>[]All rows with metadata, ignoring collapse state.
expandedItemsSet<string>Currently expanded node ids.
toggleItem(id: string) => voidToggle one node's expanded state.
expandAll() => voidExpand every collapsible node.
collapseAll() => voidCollapse every node.
hasDescendants(id: string) => booleanWhether a node has children.

useTreeSearch({ data, searchQuery, isCaseSensitive?, isRegex? })

ReturnsTypeDescription
filteredDataT[]Matching nodes plus their ancestor paths — feed into useTreeState.
searchResultsCountnumberCount of direct label matches.
isRegexValidbooleanfalse when isRegex is on and the query is not a valid pattern.
renderLabel(label: string, itemId: string) => ReactNodeLabel renderer that highlights matched substrings — pass to TreeView.
hasActiveSearchbooleanWhether a non-empty query is active.