Hierarchy Chart
Draw an org chart, a team of teams or any parent-and-children structure as a tidy tree that folds, pans and zooms.
import { HierarchyChart, HierarchyChartHandle } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use a hierarchy chart when the shape of a tree is the point: who reports to whom, which teams sit under which group, how a product breaks down. For a tree people browse and pick from (files, settings, categories), use a Tree View; for steps that depend on each other, a Flow Graph.
import { HierarchyChart } from '@youj/react'
<HierarchyChart
nodes={{
id: 'maya',
name: 'Maya Lindqvist',
role: 'CEO',
children: [
{ id: 'jonas', name: 'Jonas Okafor', role: 'VP Engineering', badge: 'Hiring', children: [/* … */] },
{ id: 'elena', name: 'Elena Petrova', role: 'VP Product' },
],
}}
selected={selected}
onSelectedChange={setSelected}
/>nodes is one root or an array of them, each { id, name, role?, avatar?, badge?, children? }; the default card shows the avatar (or the name's initials), the name, the role and the badge. Pass your own type that extends HierarchyNode and a renderNode(node, state) to draw the card yourself; state says its depth, whether it's selected, on the selected path, a branch and open, and how many nodes sit below it. Every card has one size, nodeSize (224 × 64 by default).
The layout is a tidy tree (Reingold–Tilford, in Walker's linear form): every parent is centered over its children, subtrees pack as close as the gaps allow without overlapping, and identical subtrees are drawn identically. It handles a few hundred nodes at once; layoutHierarchy(nodes, options) returns the same layout for drawing your own.
Branches are all open by default; defaultExpanded or expanded with onExpandedChange take the open ids. To find someone, hold a ref: ref.current.focusNode(id) opens the branches above them, focuses their card and centers it, and ref.current.fit() fits the chart.
Description
A company's org chart. Select a person to light their reporting line, and close a branch with the chip on a card's foot to fold it into a count ("+3").
The chart opens fitted to its canvas, but never below 60%, so names stay legible; a bigger chart opens on its root and pans instead. Drag anywhere to pan (a click that doesn't move still picks a node), use the wheel, or one finger across; zoom with Ctrl or ⌘ and the wheel, a pinch, the corner buttons or + and −, and press 0 to fit the whole chart.
orientation="horizontal" grows the tree along the reading direction (right to left under RTL). renderNode draws each card's contents (here the team, its mission and its headcount) inside the chart's card frame, which still draws focus, selection and the path.
Code
hierarchy-chart-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsnodes, renderNode, orientation… (14)
Props
| Prop | Type | |
|---|---|---|
nodesRequired | T | readonly T[]The tree: one root, or several side by side. Ids must be unique. | – |
renderNode | (node: T, state: HierarchyNodeState) => ReactNodeA node's card contents, inside the chart's card frame (which draws focus, selection and the path). Default: avatar, name, role and badge. | – |
orientation | HierarchyOrientation'vertical''horizontal'
default 'vertical' | 'vertical' |
expanded | string[]Open branches (controlled). | – |
defaultExpanded | string[]Default: every branch open. | – |
onExpandedChange | (ids: string[]) => void | – |
selected | string | nullThe selected node (controlled); | – |
defaultSelected | string | nulldefault null | null |
onSelectedChange | (id: string | null) => void | – |
nodeSize | { width: number; height: number }Every card's size in pixels. default NODE | NODE |
height | numberThe canvas height in pixels. default 480 | 480 |
label | stringThe tree's accessible name. Default: the labels' "Hierarchy chart". | – |
locale | stringDefault: the YoujProvider locale. | – |
sound | booleanWith sound on, selecting plays default true | true |
ref | Ref<HierarchyChartHandle> | – |
Other props pass through: extends ComponentProps<'div'>. | ||
StylingParts and data attributes
Styling
Parts: hierarchy-chart (with data-orientation), hierarchy-chart-viewport (with data-dragging), hierarchy-chart-world, hierarchy-chart-edges, hierarchy-chart-edge (with data-active on the selected path), hierarchy-chart-nodes, hierarchy-chart-node (with data-yj-node holding its id, data-selected, data-yj-path on the selection's ancestors, and data-state open or closed on a branch), hierarchy-chart-name, hierarchy-chart-role, hierarchy-chart-toggle (with data-state), hierarchy-chart-controls and hierarchy-chart-zoom. Connectors use the theme's strong line, and the accent on the selected path.
MotionOpen and close, zoom and fit, pan · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Open and closethe toggled node stays put while the others glide to their new places; children grow out of their parent and shrink back into it, and the connectors redraw as they move | spring.smooth0.36s, bounce 0 | 0.36s, bounce 0 | |
| Zoom, fit and focusthe view glides to its new place and scale | duration.slowease.standard340ms · cubic-bezier(0.2, 0, 0, 1) | 340mscubic-bezier(0.2, 0, 0, 1) | |
| Panthe view follows the pointer, the wheel and the pinch, never eased | no token |
Reduced motion
Nothing glides: branches open and close in place, and zoom, fit and focus land at once.
Reduced motion
Branches open and close in place, connectors are redrawn at once, and zoom, fit and focus jump to their view. Panning is unchanged, since it never animates.
AccessibilityKeyboard, ARIA
Accessibility
- The chart is a WAI-ARIA
treenamed bylabel(default "Hierarchy chart") and described by a hint that explains the keys. Each card is atreeitemwitharia-level,aria-setsize,aria-posinset,aria-selectedand, on a branch,aria-expanded. It's named by the node'snameand described by its role, its badge and, when closed, how many it hides ("3 hidden below"). - One Tab stop. ↑ and ↓ move through the nodes in reading order, → opens a branch or steps into it, ← closes it or steps out to its parent (mirrored under RTL), Home and End go to the first and last node, and * opens every sibling branch. Enter opens or closes a branch, Space selects. +, − and 0 zoom and fit.
- Focus from the keyboard brings its node into view, and closing a branch that holds the focus hands it to the branch.
- The open/close chip is a pointer shortcut for Enter, hidden from assistive technology; selection is shown by a border and a ring as well as the path's color.
- With sound on, selecting plays
select, opening a branchopenand closing itclose. - Its words come from the labels (
hierarchyChart,hierarchyChartHint,hierarchyChartHidden,hierarchyChartExpand,hierarchyChartCollapse,zoomIn,zoomOut,zoomToFit), translated by the language packs.