ComponentsEditors & drag-and-drop

Hierarchy chart

A pannable, zoomable tidy-tree diagram of any hierarchy: org charts, partner networks, decision-maker maps, site structure, branch trees. Collapsible subtrees, search highlight, focus-to-node, drag-to-reparent with a Change parent dialog as the non-drag path, viewport culling for thousands of nodes, SVG and PNG export, and a list view over the same data.

d3-hierarchy (tidy tree layout) + own pan / zoom components/hierarchy-chart.tsx, components/tree-view.tsxtheme · material · accent · density · font

Arrow keys pan the canvas, plus and minus zoom, 0 fits the chart. In the tree, arrow keys move between nodes, Shift+F10 opens node actions.

Leyla AksoyChief Executive Officer
Marcus LeeChief Technology OfficerEngineering · 24
Jonas BergEngineering Manager, Platform
Aisha BelloSenior Engineer
Erik HolmSite Reliability Engineer
Sofia MarinoEngineering Manager, Apps
Zeynep ArslanMobile Engineer
Open roleHead of Security
Priya RamanChief Financial OfficerFinance · 6
Daniel OkoyeFinancial Controller
Hannah WeissVP PeoplePeople · 5
Mei TanakaTalent Partner
Carlos MendesPeople Operations
100%

Selected: Marcus Lee, Chief Technology Officer

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { HierarchyChart, HierarchyPersonNode } from "@vamos-ui/react";

// Flat rows: { id, parentId } — parentId null for the root.
<HierarchyChart
  aria-label="Organization"
  nodes={people}
  getLabel={(p) => p.name}
  getDescription={(p) => p.title}
  renderNode={(p) => <HierarchyPersonNode name={p.name} title={p.title} src={p.photo} />}
  onReparent={(e) => movePerson(e.id, e.newParentId)}
/>

Accessibility follows the Tree view pattern on the nodes: role="tree" with levels, positions and expanded state. ↑ / ↓ go through nodes in reading order, → opens or enters, ← closes or goes to the parent, Home / End, * opens siblings, Enter or Space selects, type-ahead by first letter. The focused node is panned into view.

The canvas itself is focusable: arrow keys pan (Shift for bigger steps), + / − zoom, 0 fits. Shift+F10 on a node opens its menu (expand, center, Change parent…).

Nodes never blur; the controls are the one floating surface. Blur turns off while dragging. Reduced motion turns off animated pan and zoom.

Canvas coordinates are physical; in RTL the layout itself is mirrored so the root and the first sibling sit on the inline-start side.

Examples

Partner network

PRM: distributor → reseller → sub-reseller, left to right, with tier badges and yearly volume. In RTL the root sits on the right.

Arrow keys pan the canvas, plus and minus zoom, 0 fits the chart. In the tree, arrow keys move between nodes, Shift+F10 opens node actions.

Meridian DistributionPlatinumRotterdam€4.8M / yr
Northline ITGoldHamburg€1.2M / yr
Hafen POSSilverBremen€186K / yr
Elbe KassensystemeSilverKiel€142K / yr
Brightpath SystemsGoldLyon€980K / yr
Rhône CommerceSilverGrenoble€97K / yr
Kestrel Retail TechSilverMilan€410K / yr
100%

Drag to reparent

A CRM decision-maker map. Drag a contact onto another to change who they report to; cycles and canReparent reasons turn the target red. The node menu's Change parent… opens a searchable picker. An Undo toast restores the previous map.

Arrow keys pan the canvas, plus and minus zoom, 0 fits the chart. In the tree, arrow keys move between nodes, Shift+F10 opens node actions.

Olivia GrantDecision maker
Rafael CostaInfluencer
Ibrahim KayaBlocker
Naomi FischerChampion
Lea NovakInfluencer
Tomás RuizChampion
100%

Drag a person onto their new manager, or open a node's menu (Shift+F10) and choose Change parent.

Search and list view

A restaurant site structure. highlight marks matching nodes (locale-folded) and opens their ancestors; view="list" renders the same data with Tree view.

Arrow keys pan the canvas, plus and minus zoom, 0 fits the chart. In the tree, arrow keys move between nodes, Shift+F10 opens node actions.

Home/
Menu/menu
Breakfast/menu/breakfast
Dinner/menu/dinner
Wine list/menu/wine
Visit us/visit
Opening hours/visit/hours
Parking & access/visit/parking
Private events/events
Weddings/events/weddings
Journal/journal
100%

2,000 nodes

Large trees render only the nodes near the viewport. Here defaultCollapsed={{ depth: 1 }} starts at the directors (without it, trees beyond 500 nodes start collapsed below two levels). focusNode() opens the ancestors and pans to a person.

2,000 people · open a director to see their organization

Arrow keys pan the canvas, plus and minus zoom, 0 fits the chart. In the tree, arrow keys move between nodes, Shift+F10 opens node actions.

Robin AchterbergChief Executive Officer
100%

Export SVG / PNG

Branch structure of a multi-branch business. toSVG() returns a standalone SVG with the theme's colours resolved; toPNG(scale) renders it to a Blob.

Arrow keys pan the canvas, plus and minus zoom, 0 fits the chart. In the tree, arrow keys move between nodes, Shift+F10 opens node actions.

Head office — IstanbulSelim Kurt
Kadıköy branchEce Polat
Beşiktaş branchArda Er
İzmir regionDefne Ak
Alsancak branchCan Uslu
Bornova branchSena Toprak
100%

API

HierarchyChart

PropTypeDefault
nodes
Flat rows. Several roots are allowed; unknown parents become roots.
T[] (T extends { id, parentId })—
renderNode
Content inside the kit's node frame (selection ring, match tint, menu, collapse badge are added for you).
(node, { depth, childCount, descendantCount, collapsed, selected, matched, orientation }) => ReactNodeHierarchyNodeCard
getLabel / getDescription
Text for type-ahead, search, export, the parent picker and the list view.
(node) => stringname / label / title
isPlaceholder
Vacant / placeholder nodes get a dashed frame.
(node) => boolean—
orientation / defaultOrientation / onOrientationChange
Top-to-bottom or start-to-end. The controls toggle it.
"vertical" | "horizontal""vertical"
nodeSize
Node box in px: compact 184 × 56, card 236 × 84.
{ width, height } | "compact" | "card""card"
gap
Space between siblings and between levels.
{ x, y }{ x: 28, y: 56 }
collapsed / defaultCollapsed / onCollapsedChange
Collapsed nodes hide their subtree and show +N on the badge.
string[] / string[] | { depth } / (ids) => void{ depth: 2 } beyond 500 nodes
selected / defaultSelected / onSelectedChange
Click, Enter or Space selects. The path to the root is drawn in accent.
string | null—
focusId
Pans and zooms to this node when it changes (opens ancestors).
string | null—
highlight
Search text. Matching nodes get the accent tint; their ancestors open.
string—
onReparent
Enables drag-to-reparent and Change parent…. A promise keeps the move optimistic; a rejection rolls back with Retry.
(e: { id, newParentId, oldParentId }) => void | Promise<void>—
canReparent
A string blocks the move with that reason. Cycles are always blocked.
(e) => true | string—
nodeMenu
Extra DropdownMenuItems in each node's action menu.
(node) => ReactNode—
view
list renders the same data as a Tree view.
"chart" | "list""chart"
controls
Floating zoom, fit, orientation, expand all / collapse all.
booleantrue
height
Canvas height.
number | string"32rem"
loading / empty
Skeleton tree, or the empty message.
boolean / ReactNode—
labels
Built-in strings. Dictionary namespace: hierarchyChart.
Partial<HierarchyChartLabels>—
ref
fit(), zoomIn(), zoomOut(), focusNode(id), expandAll(), collapseAll(), toSVG(): string, toPNG(scale?): Promise<Blob>.
HierarchyChartHandle—

HierarchyPersonNode

PropTypeDefault
name / title / src
Avatar (initials fallback), name and job title.
string / string / string | null—
meta / badge
Bottom line (team size, location) and a badge after the name.
ReactNode—
vacant
Open position: dashed avatar, muted name. Pair with isPlaceholder.
boolean—

HierarchyNodeCard

PropTypeDefault
title / subtitle / meta
Three lines of text.
ReactNode—
icon / badge
Leading visual and trailing badge (tier, status).
ReactNode—

layoutHierarchy(nodes, options)

PropTypeDefault
returns
The pure tidy-tree layout, for server-side rendering or custom drawings.
{ nodes: { id, x, y, depth, parentId, … }[], width, height }—