Source Code

<div class="wrap">
  <div class="chart-head">
    <h2 class="chart-title">Organisation Chart</h2>
    <span class="chart-sub">Click any manager to collapse their team</span>
  </div>
  <div class="org" id="org">
    <ul class="tree">
      <li>
        <div class="node ceo" onclick="toggle(this)">
          <div class="node-av" style="background:linear-gradient(135deg,#6366f1,#8b5cf6)">EC</div>
          <div class="node-info"><span class="node-name">Elena Carter</span><span class="node-role">CEO</span></div>
          <span class="node-count">3</span>
        </div>
        <ul>
          <li>
            <div class="node" onclick="toggle(this)">
              <div class="node-av" style="background:linear-gradient(135deg,#0ea5e9,#06b6d4)">MR</div>
              <div class="node-info"><span class="node-name">Marcus Reed</span><span class="node-role">VP Engineering</span></div>
              <span class="node-count">3</span>
            </div>
            <ul>
              <li><div class="node leaf"><div class="node-av" style="background:linear-gradient(135deg,#f59e0b,#f97316)">AT</div><div class="node-info"><span class="node-name">Aisha Tran</span><span class="node-role">Frontend Lead</span></div></div></li>
              <li><div class="node leaf"><div class="node-av" style="background:linear-gradient(135deg,#10b981,#059669)">DK</div><div class="node-info"><span class="node-name">David Kim</span><span class="node-role">Backend Lead</span></div></div></li>
              <li><div class="node leaf"><div class="node-av" style="background:linear-gradient(135deg,#ec4899,#db2777)">RP</div><div class="node-info"><span class="node-name">Rosa Pinto</span><span class="node-role">DevOps</span></div></div></li>
            </ul>
          </li>
          <li>
            <div class="node" onclick="toggle(this)">
              <div class="node-av" style="background:linear-gradient(135deg,#8b5cf6,#a855f7)">SN</div>
              <div class="node-info"><span class="node-name">Sophie Nguyen</span><span class="node-role">VP Design</span></div>
              <span class="node-count">2</span>
            </div>
            <ul>
              <li><div class="node leaf"><div class="node-av" style="background:linear-gradient(135deg,#14b8a6,#0d9488)">JM</div><div class="node-info"><span class="node-name">Jon Marsh</span><span class="node-role">Product Designer</span></div></div></li>
              <li><div class="node leaf"><div class="node-av" style="background:linear-gradient(135deg,#f43f5e,#e11d48)">LW</div><div class="node-info"><span class="node-name">Lily Wong</span><span class="node-role">UX Researcher</span></div></div></li>
            </ul>
          </li>
          <li>
            <div class="node leaf">
              <div class="node-av" style="background:linear-gradient(135deg,#64748b,#475569)">TB</div>
              <div class="node-info"><span class="node-name">Tom Baker</span><span class="node-role">VP Sales</span></div>
            </div>
          </li>
        </ul>
      </li>
    </ul>
  </div>
</div>

Org Chart — Free HTML CSS JS Tree Snippet

Org Chart · Layouts · Plain HTML, CSS & JS · Live preview

What's included

Features

Pure-CSS connector lines via: :before/::after pseudo-elements
Nested <ul> structure — semantic and naturally recursive
:first-child/:last-child trimming for clean sibling connectors
Centred flex layout auto-distributes nodes symmetrically
Click-to-collapse branches with: scope > ul targeting
Direct-report count badges that dim when collapsed
Distinct CEO root styling and non-interactive leaf nodes
Horizontal scroll container for wide hierarchies

About this UI Snippet

Org Chart — CSS Connector Tree, Collapsible Branches & Report Counts

Screenshot of the Org Chart snippet rendered live

An organisation chart visualises reporting hierarchy — who reports to whom — and is a staple of HR tools, company about pages, team directories, and admin dashboards. This snippet builds a complete, collapsible org chart using nothing but nested HTML lists and CSS for the connector lines, with avatars, names, roles, direct-report count badges, and click-to-collapse branches.

The pure-CSS connector tree

The hierarchy is a nested unordered list, and the connecting lines are drawn entirely with CSS pseudo-elements — no SVG, canvas, or library. Each list item gets a vertical line above it (::before) descending from its parent, and a horizontal line (::after) that joins siblings. Clever use of :first-child and :last-child trims the horizontal line so it spans only between the outermost siblings, and :only-child hides the connectors entirely for a single report. This is the classic CSS tree technique, refined to look clean at every branch.

Centred flex layout

Each level is a flex row with justify-content: center, and each node stacks its children below it centred. This produces the symmetrical top-down org chart layout automatically — the browser handles the horizontal distribution, so adding or removing people never requires manual positioning. A horizontal scroll container handles wide charts gracefully on smaller screens.

Collapsible branches

Clicking a manager node toggles a collapsed class on its child list, hiding the entire subtree, and adds a state class to dim the report-count badge. The toggle() function uses the :scope > ul selector to target only the node's direct child list — essential in a recursive tree so collapsing one manager does not affect nested teams. Leaf nodes (individual contributors with no reports) are non-interactive.

Report-count badges

Managers show a small badge with their number of direct reports, positioned at the top-right corner of their node. The badge dims when the branch is collapsed, signalling that there is a hidden team beneath. This gives an at-a-glance sense of team size and span of control without expanding every branch.

Visual hierarchy

The CEO node gets a distinct subtle gradient and accent border to mark the root. Avatars use gradient backgrounds with initials, avoiding image dependencies. Hover lifts interactive nodes with a shadow, while leaf nodes stay flat to communicate that they are not clickable.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not have to trace the connector geometry in your head. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the tree li::before and li::after pseudo-elements combine with the first-child and last-child width trimming to draw a clean horizontal sibling bar with no SVG, or why toggle uses the scope greater-than ul selector instead of a plain querySelector on a recursively nested list. The same assistant is useful for optimizing it too, for example weighing whether rendering a very deep or wide chart calls for virtualizing collapsed branches so hidden subtrees are not sitting fully in the DOM. It is equally good at extending the effect: ask it to add drag-and-drop re-parenting of a node, generate the nested lists recursively from a flat employee array with manager ids, or add keyboard navigation between sibling nodes. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a collapsible "org chart" tree in plain HTML and CSS, using nested unordered lists as the only structure and CSS pseudo-elements as the only connector lines — no SVG, no canvas, no charting library.

Requirements:
- The hierarchy must be marked up as nested <ul><li> lists: a manager's list item contains a nested <ul> whose <li> children are their direct reports, recursively.
- Draw a vertical line above every non-root list item using a ::before pseudo-element, and a horizontal sibling-connector line using an ::after pseudo-element on the parent <ul>'s list items. The horizontal line must be trimmed with the first-child selector so it only extends from center to the right, and with the last-child selector so it only extends from the left to center, so the joining bar spans exactly between the outermost siblings and does not overhang past them. A lone-child list item (matched with only-child) must hide both connector lines entirely.
- Lay out each level as a centered flex row so the whole tree distributes and re-centers itself automatically as nodes are added or removed, with no manual position math.
- Each manager node must be clickable and display a badge showing its number of direct reports. Clicking a manager must toggle a collapsed class on its own direct child ul only — selected using the colon-scope greater-than ul combinator so that toggling one manager's subtree never affects a nested manager's own independently-collapsed team.
- Leaf nodes (people with no reports) must not be clickable and must render with no report-count badge.
- Give the root node distinct styling from every other node so the top of the hierarchy is visually obvious.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Explore the hierarchyThe chart shows the full reporting structure top-down from the CEO. Each manager displays a badge with their number of direct reports.
  2. 2
    Collapse and expand teamsClick any manager node to collapse their team and hide the subtree. Click again to expand. The report-count badge dims while collapsed.
  3. 3
    Add a personAdd an <li> inside the appropriate parent's <ul>. Give it a .node with an avatar, name, and role. If they manage people, add a nested <ul> and a .node-count badge; if not, add the .leaf class.
  4. 4
    Rebuild from dataFor dynamic charts, render the nested lists from a hierarchical data array. Walk the tree recursively, emitting an <li> with a node for each person and a nested <ul> for their reports.
  5. 5
    Style and brandRecolour the connector lines, node borders, and the CEO accent. Swap avatar gradients for real profile photos by replacing the initials div with an <img>.
  6. 6
    Export for your frameworkClick "JSX" for a React component that renders the tree recursively from a data array. Click "Vue" for a Vue 3 SFC using a recursive component.

Real-world uses

Common Use Cases

HR platform and team directory
Render a company's reporting structure from your HR system. Link each node to the employee's profile, show open positions as dashed placeholder nodes, and let managers collapse other departments to focus on their own. The report counts give leadership a quick view of team sizes and span of control.
Company about page and team showcase
Display your team structure on a public about or careers page. Swap initials for real photos and link roles to open job postings under each team. The collapsible branches keep a large org compact while letting visitors drill into areas they care about.
Admin dashboard permission and role hierarchy
Adapt the tree to visualise role inheritance or permission hierarchies — who can manage whom, or how access cascades. The collapse mechanic helps admins navigate deep permission trees, and the badges can show the number of users in each role group.
Render from a hierarchical data source
Feed the chart from an API returning a nested employee tree (or a flat list with managerId you build into a tree). Walk the structure recursively to emit the nested lists. Add drag-and-drop to reassign reporting lines, persisting the new managerId back to your backend.
Study the pure-CSS tree connector technique
Drawing tree connectors with only pseudo-elements and child-position selectors is an elegant, dependency-free technique. The snippet shows exactly how the vertical and horizontal lines are composed and trimmed. It transfers to family trees, category taxonomies, decision trees, and file explorers like the tree menu and tree table.
Mind map or category taxonomy viewer
The same nested-list-plus-CSS-connectors approach renders any hierarchy: a content taxonomy, a product category tree, or a simple mind map. Replace the person nodes with topic cards and the chart becomes a collapsible knowledge map.
Related: CSS text-wrap: balance Demo
See the CSS text-wrap: balance Demo for a related layouts pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Each tree node is a list item. A ::before pseudo-element draws a short vertical line descending from the parent into the node, and a ::after draws a horizontal line that connects siblings. The horizontal line is trimmed with :first-child (line only on the right half) and :last-child (only on the left half) so the connector spans precisely between the outermost siblings. :only-child hides both lines for a lone report. This composition of pseudo-elements and position selectors creates the entire connector system in CSS alone.

The org chart is a recursively nested structure — a manager's list item contains a <ul> of reports, and those reports may contain their own <ul>s. A plain querySelector("ul") from a node would match the first descendant list anywhere in the subtree, potentially collapsing the wrong level. li.querySelector(":scope > ul") restricts the match to the node's immediate child list, so toggling collapses exactly that manager's direct team and leaves nested teams' own collapse states untouched.

If your data is a flat array where each employee has an id and a managerId, first build a tree: group employees by managerId, then recursively attach each person's reports. Starting from the root (the employee with no manager), emit an <li> with the person's node and, if they have reports, a nested <ul> containing their reports rendered the same way. This recursive render mirrors the nested-list markup the CSS expects.

Model the org as a nested data structure where each person has a reports array. Create a recursive OrgNode component that renders the person's card and, if they have reports, maps over them rendering an OrgNode for each inside a child list — the recursion produces the nested <ul> markup the CSS connectors rely on. Track collapsed node ids in state (a Set) and conditionally add the collapsed class. Reuse the exact CSS for the connector lines.