Org Expander
- Stable
- WCAG 2.2 evidence
- RTL
The button that shows or hides a manager's direct reports in an organisation chart: a pill with a plus or minus and the number of reports. Built on React Aria Button: Enter and
Space press it, disabled leaves the tab order, keyboard focus shows the focus ring (WCAG 2.1.1, 2.4.7, 4.1.2). The pill is 22 px tall; a transparent extension makes the pointer target 24 px (2.5.8). Colour does not carry the state:
the icon (plus or minus) and the name (aria-expanded, or Expand and Collapse in the name) do (1.4.1). Consumer duties: name it after what it opens, include the count in the name, and, when you also set aria-controls, point
it at the group of reports. Inside an OrgChart, OrgNode renders and wires this button for you.
import { OrgExpander } from "@nexera-ui/react";- 6
- examples
- 23
- props
- 3
- live controls
- 1
- platform
- 8
- WCAG criteria
- 0
- blocks use 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 { OrgExpander } from "@nexera-ui/react";
<OrgExpander />Examples 5
The same examples as Storybook, rendered live. Open Code to copy one.
Controlled
Controlled by a parent that shows the reports. The name is fixed ("Sara Malik's reports (3)") and aria-expanded carries the state, which is the disclosure pattern.
import { useState } from "react";
import { OrgExpander } from "@nexera-ui/react";
export function Controlled() {
function Branch() {
const [open, setOpen] = useState(false);
return (
<div className="flex max-w-xs flex-col items-start gap-3">
<span className="text-body-strong text-primary">Sara Malik, Head of People</span>
<OrgExpander
count={3}
aria-label="Sara Malik's reports (3)"
aria-controls="sara-reports"
isExpanded={open}
onExpandedChange={setOpen}
/>
<ul
id="sara-reports"
hidden={!open}
className="text-body-small text-secondary m-0 list-none p-0"
>
<li>Bilal Ahmed</li>
<li>Hina Raza</li>
<li>Omar Farooq</li>
</ul>
</div>
);
}
return <Branch />;
}
Action name
The name can instead state the action and change with the state ("Expand..." then "Collapse..."). Then aria-expanded is left off, because the name already carries the state. This is what OrgNode uses inside an OrgChart.
import { OrgExpander } from "@nexera-ui/react";
export function ActionName() {
return (
<OrgExpander
count={12}
expandLabel="Expand Sara Malik's reports (12)"
collapseLabel="Collapse Sara Malik's reports (12)"
/>
);
}
Disabled
Disabled: leaves the tab order and ignores presses.
import { OrgExpander } from "@nexera-ui/react";
export function Disabled() {
return (
<div className="flex flex-wrap items-center gap-6">
<OrgExpander count={12} aria-label="Collapsed: reports (12)" isDisabled />
<OrgExpander count={12} aria-label="Expanded: reports (12)" isDisabled isExpanded />
</div>
);
}
Long count
Long counts: the pill grows with its content and never truncates (whitespace-nowrap, hugging width).
import { OrgExpander } from "@nexera-ui/react";
<OrgExpander count="1,248" aria-label="Company reports (1,248)" />;
Right to left
Right-to-left: the icon and the count swap sides, and the number keeps its digits.
import { OrgExpander } from "@nexera-ui/react";
export function RightToLeft() {
return (
<div dir="rtl" lang="ar" className="flex flex-wrap items-center gap-6">
<OrgExpander count="12" aria-label="مرؤوسو سارة (12)" />
<OrgExpander count="12" aria-label="مرؤوسو سارة (12)" isExpanded />
</div>
);
}
Props 23
Press "Try it" on a card to load that prop into the playground.
23 props shown
countNexerastring | numberNumber of reports the branch holds, shown next to the plus or minus. Keep it in the accessible name too, so the visible text is part of the name (WCAG 2.5.3). Omit it to show the icon alone.
isExpandedNexerabooleanWhether the branch is expanded. Controlled: pair it with
onExpandedChange.
defaultExpandedNexerabooleanWhether the branch is expanded at first render (uncontrolled).
onExpandedChangeNexera(isExpanded: boolean) => voidCalled with the new state when the button is pressed (pointer, Enter or Space).
classNameNexerastringExtra classes, merged last so they win over the defaults.
styleNexeraCSSPropertiesInline style.
aria-labelNexerastringAccessible name that stays the same in both states ("Jane Doe's reports (4)"); aria-expanded carries the state. Translate it.
aria-labelledbyNexerastringId(s) of the element(s) that name the button; wins over aria-label.
Id(s) of the element(s) that name the button (for example the manager's name); aria-expanded carries the state.
expandLabelNexerastringAccessible name while collapsed, for example "Expand Jane Doe's reports (4)". Translate it.
collapseLabelNexerastringAccessible name while expanded, for example "Collapse Jane Doe's reports (4)". Translate it.
isDisabledReact AriabooleanWhether the button is disabled.
onPressReact Aria(e: PressEvent) => voidHandler that is called when the press is released over the target.
onPressStartReact Aria(e: PressEvent) => voidHandler that is called when a press interaction starts.
onPressEndReact Aria(e: PressEvent) => voidHandler that is called when a press interaction ends, either over the target or when the pointer leaves the target.
onPressChangeReact Aria(isPressed: boolean) => voidHandler that is called when the press state changes.
onPressUpReact Aria(e: PressEvent) => voidHandler that is called when a press is released over the target, regardless of whether it started on the target or not.
autoFocusReact AriabooleanWhether the element should receive focus on render.
typeReact Aria"button" | "submit" | "reset"The behavior of the button when used in an HTML form.
formReact AriastringThe <form> element to associate the button with.
The value of this attribute must be the id of a <form> in the same document.
See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button#form).
nameReact AriastringSubmitted as a pair with the button's value as part of the form data.
valueReact AriastringThe value associated with the button's name when it's submitted with the form data.
idReact AriastringThe element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id).
aria-describedbyReact AriastringIdentifies the element (or elements) that describes the object.
* 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
6 direct · 2 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.2Meaningful SequenceLevel A · supporting test
- 1.4.1Use of ColorLevel A · tested directly
- 2.1.1KeyboardLevel A · tested directly
- 2.4.7Focus VisibleLevel AA · tested directly
- 2.5.3Label in NameLevel A · tested directly
- 2.5.8Target Size (Minimum)Level AA · supporting test
- 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-disableddata-hovereddata-pressed
<OrgExpander className="data-disabled:opacity-90 shadow-sm" />Used in blocks
No block uses OrgExpander yet.
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.