Org Node
- Stable
- WCAG 2.2 evidence
- RTL
One person (or open position) of an organisation chart. A card with an avatar, the name, the role, a department badge and a report count; nested OrgNode
children are its direct reports. **Inside an OrgChart** the node is a tree item (role="treeitem" with aria-level, aria-setsize, aria-posinset,
aria-expanded when it has reports and aria-selected when you pass isSelected), named by the name and role and described by
the department and report count. Its reports sit under it, joined by decorative connectors, behind an OrgExpander that is a
real button. Pressing a node that has reports and no onPress or href expands or collapses it. **On its own** it draws only the card: plain text when static, a React Aria button when it has onPress, a link when it has
href. Hover is data-hovered, keyboard focus a 2 px inside ring plus the halo, and the selected state is
isSelected (WCAG 2.1.1, 2.4.7, 4.1.2). Selection and a vacancy are shown by fill, stroke and text ("Open role"), never by
colour alone (1.4.1).
import { OrgNode } from "@nexera-ui/react";- 10
- examples
- 19
- props
- 4
- live controls
- 1
- platform
- 10
- WCAG criteria
- 1
- block uses it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { OrgNode } from "@nexera-ui/react";
<OrgNode />Examples 9
The same examples as Storybook, rendered live. Open Code to copy one.
Compact
The compact card: 200 px wide, a 32 px avatar, name and role only.
import { OrgNode } from "@nexera-ui/react";
export function Compact() {
return <OrgNode variant="compact" name="Sara Malik" jobTitle="Head of People" />;
}
Vacant
An open position: "Open role" is text, with a user-x icon and the department in a warning badge.
import { OrgNode } from "@nexera-ui/react";
export function Vacant() {
return <OrgNode variant="vacant" jobTitle="Senior backend engineer" department="Engineering" />;
}
Selected
Selected: a tinted fill, a 2 px brand stroke and aria-current; the text is not coloured alone.
import { OrgNode } from "@nexera-ui/react";
<OrgNode
name="Sara Malik"
jobTitle="Head of People"
department="People"
reports="8 reports"
isSelected
/>;
As button
A button that opens the person's panel: Tab to it, Enter or Space presses. The name and role name it; the rest describes it.
import { OrgNode } from "@nexera-ui/react";
<OrgNode
name="Sara Malik"
jobTitle="Head of People"
department="People"
reports="8 reports"
onPress={() => undefined}
/>;
As link
A link to the person's page.
import { OrgNode } from "@nexera-ui/react";
<OrgNode
name="Sara Malik"
jobTitle="Head of People"
department="People"
reports="8 reports"
href="#sara-malik"
/>;
With photo
A photo through the avatar slot (an Avatar of size="lg", decorative because the name is next to it).
import { Avatar, OrgNode } from "@nexera-ui/react";
const PHOTO = `data:image/svg+xml,${encodeURIComponent(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect width="40" height="40" fill="steelblue"/>' +
'<circle cx="20" cy="15" r="7.6" fill="white" fill-opacity="0.92"/>' +
'<ellipse cx="20" cy="38" rx="15.6" ry="12" fill="white" fill-opacity="0.92"/></svg>',
)}`;
export function WithPhoto() {
return (
<OrgNode
name="Sara Malik"
jobTitle="Head of People"
department="People"
reports="8 reports"
avatar={<Avatar type="photo" src={PHOTO} initials="SM" size="lg" isDecorative />}
/>
);
}
Long content
Long content wraps and the card grows.
import { OrgNode } from "@nexera-ui/react";
<OrgNode
name="Alexandria Ocasio-Cortez-Hernandez-Villanueva"
jobTitle="Senior principal staff engineer, platform reliability and developer experience"
department="Platform reliability engineering"
reports="128 direct and indirect reports"
/>;
Right to left
Right-to-left: the avatar moves to the right, the report count to the left, the text aligns to the start.
import { OrgNode } from "@nexera-ui/react";
export function RightToLeft() {
return (
<div dir="rtl" lang="ar" className="flex flex-wrap items-start gap-4">
<OrgNode
name="سارة مالك"
jobTitle="رئيسة الموارد البشرية"
department="الموارد البشرية"
reports="8 مرؤوسين"
/>
<OrgNode variant="compact" name="سارة مالك" jobTitle="رئيسة الموارد البشرية" />
<OrgNode variant="vacant" name="وظيفة شاغرة" jobTitle="مهندس خلفي" department="الهندسة" />
</div>
);
}
Narrow width
Narrow container (320 px): the card shrinks to the container (max-w-full) and the text wraps.
import { OrgNode } from "@nexera-ui/react";
export function NarrowWidth() {
return (
<div className="flex max-w-xs flex-col gap-4">
<OrgNode
name="Alexandria Ocasio-Cortez"
jobTitle="Senior principal staff engineer"
department="Platform"
reports="128 reports"
/>
<OrgNode
variant="compact"
name="Alexandria Ocasio-Cortez"
jobTitle="Senior principal staff engineer"
/>
</div>
);
}
Props 19
Press "Try it" on a card to load that prop into the playground.
19 props shown
idNexeraKeyIdentifies the node inside an OrgChart: the key used by expandedKeys, defaultExpandedKeys and onExpandedChange. Give
every node that has reports a stable one (an employee id); without it the node still works but its expansion cannot be
controlled from outside.
jobTitleNexerastringThe person's role or the open position. Wraps
onto more lines instead of being truncated. Named jobTitle because role is the HTML attribute.
isSelectedNexerabooleanWhether the node is the selected one: nav/active-bg with a 2 px brand stroke. Inside a chart it
becomes aria-selected, so pass a boolean on every node when your chart supports selection (and nothing when it does not);
on a standalone card it becomes aria-current. Hover and focus are pointer and keyboard states that React Aria drives.
lineStyleNexera"solid" | "dotted"Line style of the connector that joins this node to its manager: solid, or dotted for a
secondary, dotted-line relationship. Only used inside a chart. The line is decorative: also say a dotted relationship in
text (for example in jobTitle) (WCAG 1.4.1).
directReportsNexeranumberNumber of direct reports shown on the expander. Defaults to the number of OrgNode children. Set it when the reports load
lazily: a node with a count above zero is expandable even before its children exist; render the children once
onExpandedChange reports the node as expanded.
expandLabelNexerastringName of the expander button while the node is collapsed. Translate it.
collapseLabelNexerastringName of the expander button while the node is expanded. Translate it.
childrenNexeraReactNodeThe node's direct reports, as OrgNode elements (not fragments). They are drawn, with their connectors, under the node while
it is expanded, and only inside an OrgChart: a standalone node draws only its card.
classNameNexerastringExtra classes for the card, merged last so they win over the defaults.
styleNexeraCSSPropertiesInline style for the card.
variantNexera"default" | "compact" | "vacant"Presentation: default is the 240 px card, compact a 200 px row without department and reports, vacant
an open position.
The compact card: 200 px wide, a 32 px avatar, name and role in one row.
An open position: a dashed-look card on bg/page with a user-x icon and the department in a warning badge.
nameNexerastringThe person's name. Names the node. Wraps instead of truncating. The person's name. What the card says in place of a name. Translate it. The text is what tells people the position is vacant, not the colours (WCAG 1.4.1).
avatarNexeraReactNodeThe avatar. Pass an Avatar of size="lg" (40 px) with isDecorative to show a
photo. By default the initials of name are drawn.
The avatar: an Avatar of size="md" with isDecorative.
Not used: a vacancy has a user-x icon instead.
departmentNexeraReactNodeDepartment. Shown when provided; the text is the badge's label. Not shown in the compact card. Department of the position.
reportsNexerastringReport count: shown with a people icon when provided. Write the whole phrase, translated ("8 direct reports"). Not shown in the compact card. Not shown on a vacancy.
onPressNexera((event: PressEvent) => void) | ((event: PressEvent) => void)Called when the card is pressed (pointer, Enter or Space). The card becomes a button, or a tree item that runs this. Also called when the link is pressed.
hrefNexerastringThe card becomes a link to this URL (inside a chart, a tree item with a link over it; Enter follows it).
targetNexerastringLink target.
relNexerastringLink relationship.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
8 direct · 2 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.3.2Meaningful SequenceLevel A · tested directly
- 1.4.1Use of ColorLevel A · tested directly
- 1.4.10ReflowLevel AA · supporting test
- 1.4.12Text SpacingLevel AA · supporting test
- 2.1.1KeyboardLevel A · tested directly
- 2.4.7Focus VisibleLevel AA · tested directly
- 2.5.3Label in NameLevel A · tested directly
- 4.1.2Name, Role, ValueLevel A · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
data-focus-visibledata-hovereddata-selected
<OrgNode className="data-focus-visible:opacity-90 shadow-sm" />Used in blocks
Related components
- AccordionItemOne collapsible section of an FAQ or settings page.
- AreaChartA stacked area chart: layers piled up over time with the title, range switch, actions and legend of the card.
- AvailabilityRowOne person's availability across a window of the day: an avatar with initials and the name, and a timeline with the busy periods drawn as bars.
- AvatarA person or organisation shown as a photo, initials or an icon.
- AvatarGroupA row of overlapping avatars with a "+N" chip for the rest.
- AvatarLabelAn avatar with a name and an optional subtitle beside it, for a person in a list, a header or a mention.
- BadgeShort status or category label: `Tone` x `Variant` x `Size`, with an optional dot, leading icon and remove button.
- BadgeGroupA pill that pairs a small badge with a short message, for an announcement or a status line.