A Storybook addon that draws anatomy diagrams for your components. Mark the
parts with data-slot, set one story parameter, and every part
gets a labelled callout in a gutter outside the frame — reached by a leader
that provably never crosses another.
Design-system docs live and die by their anatomy diagrams, and today they are
drawn by hand in Figma — re-measured and re-laid-out every time a component
changes. react-anatomy draws them right in Storybook, from the live DOM. Turn
it on for a story and it discovers the parts, lays out the labels, routes the
leaders, and outlines each region. Nothing is hand-placed, so nothing goes stale.
- Zero coupling. The addon reads
data-slotattributes off the rendered DOM. It never imports your components and never needs to know what they are. - Leaders that cannot cross. Every leader leaves its region perpendicular to the nearest rail; because each fan on a side spans one x-interval, order is preserved and crossings are impossible — a geometric guarantee, not a heuristic.
- Deterministic. The placement is a pure function of the geometry, the label sizes, and a set of constants. Same input, identical output, every render — diagrams that are safe to snapshot.
- The component never moves. Gutters are reserved before the layout solves, so turning the overlay on doesn't shift the thing you're documenting by a pixel.
- Navigable or static. Leave it navigable and the reader drills a level at a
time with breadcrumbs; pin a
depthfor a fixed diagram to embed in docs.
npm install @react-anatomy/storybookRegister the addon's decorator in your Storybook preview. It derives the label from the story context, so there is nothing to name by hand:
// .storybook/preview.tsimport{decorators}from"@react-anatomy/storybook/preview";exportdefault{ decorators };Mark the parts of your component with data-slot — that is the entire contract:
functionCard({ children }){return(<div><divdata-slot="media">{/* … */}</div><divdata-slot="heading">{/* … */}</div><divdata-slot="body">{/* … */}</div><divdata-slot="footer">{/* … */}</div></div>);}Then set the slotAnnotations parameter on a story. On its own it opens on the
outermost slots and lets the reader drill in a level at a time — click a part
to dive into it, and the breadcrumb trail walks back out. Every level is
re-labelled from scratch, leaders and all. boundary outlines the component's
own edge:
exportconstAnatomy={parameters: {slotAnnotations: {boundary: true}},render: ()=><Card>{/* … */}</Card>,};Pin a depth instead for a static diagram. "all" labels the full tree at once
— nested regions and all — in the same non-crossing construction:
exportconstAnatomyAll={parameters: {slotAnnotations: {depth: "all"}},render: ()=><Card>{/* … */}</Card>,};Or focus on one part with scope — the labels route out to the sides when the
parts are packed together in a row:
exportconstHeadingAnatomy={parameters: {slotAnnotations: {scope: "heading"}},render: ()=><Card>{/* … */}</Card>,};Set slotAnnotations to true for the outermost slots, or to an object:
| Option | Type | Default | Description |
|---|---|---|---|
scope | string | outermost | Annotate the slots inside the element carrying this data-slot. |
depth | number | "all" | navigable | Nesting levels to show. Omit for the drill-down; set for a static diagram. |
boundary | boolean | false | Outline the component's own edge. |
gutters | "reserved" | "fitted" | "reserved" | "fitted" crops the gutters to the labels (needs a pinned depth). |
The root breadcrumb is taken from the story context — the scope when there is
one, otherwise the last segment of the story title.
pnpm install
pnpm build # build the packages
pnpm test# the placement + collection suites (vitest)
pnpm lint # eslint (--max-warnings=0) + prettier + knip + depcheck
pnpm storybook # the playground, consuming the built packagesRequires Node 24 and pnpm 11.8.0 (provisioned via devEngines).
MIT licensed.




