Accessible Org Charts and Hierarchy Diagrams

Permalink to "Accessible Org Charts and Hierarchy Diagrams"

Org charts, reporting structures, product taxonomies and decision trees are drawn as boxes connected by lines, but they are hierarchies — data that ARIA already knows how to express. The accessible approach is not to describe the drawing; it is to present the same hierarchy as a tree or nested list that screen reader users can navigate by level, with the visual chart as a parallel view. When the two share data and focus, everyone works with the same structure.

This guide belongs to accessible network & graph diagrams.

Spec reference

Permalink to "Spec reference"
  • SC 1.3.1 Info and Relationships (A) — reporting relationships must be programmatic: a nested list or a tree with levels.
  • SC 1.1.1 Non-text Content (A) — the visual chart’s text alternative is the tree plus a summary.
  • SC 2.1.1 Keyboard (A) — expand, collapse and inspect people or units without a pointer.
  • SC 1.4.10 Reflow (AA) — wide charts must not require two-dimensional scrolling at 400% zoom; the tree view reflows naturally.
  • ARIA tree pattern — for interactive hierarchies; a nested ul suffices for static ones.
An org chart as a tree Hierarchy: the CEO with two direct reports — VP Engineering with two teams, VP Sales with one team — and a dotted-line relationship noted in text. An org chart as a treeAna Ruiz, CEO3 direct reports, 142 people in totalLi Wei, VP Engineering2 teams, 88 peoplePlatform team34 peopleProduct team54 people; dotted line to VP SalesSam Okafor, VP Sales1 team, 41 peopleEMEA sales41 people
Reporting lines become levels; dotted lines become described relationships.

When to use — and when not to

Permalink to "When to use — and when not to"

Present any hierarchy diagram with a tree or nested list equivalent. For static, small charts (a team page), a nested list with role and team size is enough. For large, interactive charts (a company directory), use the tree pattern with lazy loading and search.

Do not describe the chart in a paragraph (“The CEO is at the top; below her are…”) beyond a dozen people; it does not scale and cannot be navigated. Do not use an edge table for strict hierarchies — levels are clearer as a tree.

The misapplication: a canvas-drawn org chart with a single “Organisation chart” alt text and pan-and-zoom as the only navigation.

Image org chart versus tree-backed org chart Comparison: an image or canvas chart with alt text gives no structure or navigation; a tree-backed chart provides levels, team sizes, search and synchronised focus. Image org chart versus tree-backed org chart✗ Image or canvas chartAlt: "Organisation chart"Pan and zoom to exploreTwo-dimensional scrolling at zoomDotted lines only drawn✓ Tree-backed chartTree: "Li Wei, VP Engineering, level 2, 1 of2"Arrow keys and searchTree reflows verticallyDotted lines described in text

Annotated code example

Permalink to "Annotated code example"
<section aria-labelledby="org-h">
  <h2 id="org-h">Organisation</h2>
  <p>142 people. Ana Ruiz (CEO) has 3 direct reports.</p>                  <!-- summary -->
  <ul role="tree" aria-label="Reporting lines">                            <!-- SC 1.3.1 -->
    <li role="treeitem" aria-expanded="true" tabindex="0">
      Ana Ruiz, CEO <span class="meta">— 3 direct reports, 142 people</span>
      <ul role="group">
        <li role="treeitem" aria-expanded="false" tabindex="-1" aria-describedby="dl-1">
          Li Wei, VP Engineering <span class="meta">— 2 teams, 88 people</span>
          <span id="dl-1" class="visually-hidden">Product team also reports to Sam Okafor (dotted line).</span>
          <ul role="group" hidden>…</ul>
        </li>
      </ul>
    </li>
  </ul>
</section>
<!-- Visual chart rendered from the same data; aria-hidden because the tree is the equivalent -->
<div class="org-canvas" aria-hidden="true"></div>
// Keep the visual chart in sync with tree focus (and vice versa)
tree.addEventListener('focusin', (e) => {
  const id = e.target.closest('[role="treeitem"]')?.dataset.id;
  if (id) chart.centerOn(id).highlight(id);                 // sighted keyboard users see where they are
});
chart.on('nodeclick', (id) => focusTreeItem(id, { expandAncestors: true }));

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"
Event Expected announcement AT deviations
Tab into tree “Reporting lines, tree, Ana Ruiz, CEO — 3 direct reports, 142 people, expanded, level 1” —
Right / Down Expand / next “Li Wei, VP Engineering — 2 teams, 88 people, collapsed, level 2”
Pause on Li Wei Description: dotted line Read after a pause
Search “Okafor” Focus moves to Sam Okafor; ancestors expanded —
Hierarchy representations by chart size Matrix of chart sizes — up to 10 people, up to 100, thousands — against nested list, tree widget, search and visual chart. Hierarchy representations by chart sizeNested listTree widgetSearchVisual chartUp to 10EnoughOptionalNot neededUsefulUp to 100LongRecommendedHelpfulUsefulThousandsUnusableRequired with lazyloadingRequiredLocal views only
Larger hierarchies need the tree pattern and search; the picture becomes secondary.

Integration context

Permalink to "Integration context"

The tree behaviour comes from the tree role for category and file browsers and, for large organisations, lazy-loading tree nodes with aria-busy. Non-hierarchical relationships belong in a graph with adjacency tables. Selecting a person often opens a profile in a side panel — see master-detail & split views.

Gotchas

Permalink to "Gotchas"

Dotted lines and matrix organisations. A person with two managers breaks a strict tree. Place them under their primary manager and describe the secondary line in text, or show them in both places with “(also listed under …)”.

Photos. Profile photos are decorative in an org chart when names are present; use alt="".

Vacancies. “Open role” boxes need text: “Vacant: Senior engineer, Platform team”.

Common mistakes

Permalink to "Common mistakes"
  • An image of the chart with a one-line alt text.
  • Indentation-only structure with no levels.
  • Dotted lines visible only as dashed strokes.
  • Pan-and-zoom as the only navigation.

Framework notes

Permalink to "Framework notes"

Libraries like d3-org-chart, OrgChart.js and GoJS render visual charts; none provides an accessible tree. Render the tree with your accessible tree component (React Aria, Angular CDK) from the same data and hide the canvas from AT with aria-hidden="true" once the tree is the equivalent. Synchronise selection both ways.

const chart = new OrgChart().container('.org-canvas').data(people).onNodeClick(id => focusTreeItem(id)).render();

Worked example

Permalink to "Worked example"

An HR portal’s org chart was a zoomable SVG of 1,800 people with no text equivalent. A blind manager could not find her own skip-level reports. The portal added a “Reporting lines” tree beside the chart, lazy-loaded below the second level, with search by name and role, team sizes in each item, and dotted-line relationships as descriptions. Focus in the tree centres the visual chart on the same person, so sighted colleagues on a call can follow along.

Testing checklist

Permalink to "Testing checklist"

Design system notes

Permalink to "Design system notes"

Offer a HierarchyView that renders a tree from hierarchical data and optionally a visual chart from the same data, with focus synchronisation. Teams then cannot ship a chart without its tree.

FAQ

Permalink to "FAQ"
Should the visual chart be hidden from screen readers?

If an equivalent tree is present, hiding the canvas or SVG avoids duplicated or meaningless output. Keep a short label on the figure.

Nested list or tree widget?

Nested list for small, static charts; tree widget for interactive or large ones.

How do I show headcount?

In each item’s text: “2 teams, 88 people”. Users use it to understand scope without expanding.

What about decision trees?

The same approach: a tree where each node states the question or outcome, with branch labels as part of child names (“If yes: …”).

Do org charts need search?

Beyond a hundred people, yes.

Can the tree replace the chart entirely?

For many users, yes. Keep the chart for those who benefit from the spatial view.

How do I show reporting changes over time?

Offer a date selector and announce changes as a summary (“3 people moved to Platform team since 1 September”), with a table of moves. Animating boxes between positions is not an accessible way to show change.

Permalink to "Related"

← Back to Accessible Network & Graph Diagrams