Component Anatomy

Rendering customization

Zero-config by default, themable in one line, fully hookable when you need it. See it live on the theming demo.

The layering model

Every visual decision resolves in this order (lowest → highest priority):

  1. Default look — the built-in indigo style. Nothing to configure.
  2. Global CSS variables — set --ca-* on :root for a page-wide brand.
  3. Preset — a named token bundle passed per instance.
  4. Theme tokens — individual overrides passed per instance.

1. Presets

createAnatomy({ root, panel, preset: 'blueprint' });
PresetLook
defaultIndigo fill + solid border, filled label chip.
minimalNo fill, thin neutral border, subdued gray label.
contrastYellow/black, thick square border. High visibility.
blueprintBlue dashed outline on a light wash — technical drawing style.

Presets are plain objects — import, spread, and tweak them:

import { presets } from '@component-anatomy/core';
createAnatomy({ root, theme: { ...presets.blueprint, labelBg: '#0f172a' } });

2. Theme tokens

The accent shorthand derives the overlay border, a 15% background wash, and the label background from a single brand color:

createAnatomy({ root, panel, theme: { accent: '#0d9488' } });
TokenTypeMaps to
accentcolorShorthand → border, bg wash, label bg
overlayBgcolor--ca-overlay-bg
overlayBordercolor--ca-overlay-border
overlayBorderWidthpx | CSS length--ca-overlay-border-width
overlayBorderStylesolid | dashed | dotted--ca-overlay-border-style
overlayRadiuspx | CSS length--ca-overlay-radius
labelBg / labelFgcolor--ca-label-bg / --ca-label-fg
labelFont / labelFontSizefont | px--ca-label-font / --ca-label-font-size
zIndexnumber--ca-overlay-z
transitionMsms | CSS time--ca-transition

Numbers get sensible units automatically (88px, 300300ms for transitionMs).

Runtime switching

controller.setTheme({ accent: picker.value }, 'minimal');

Global CSS variables (no JS)

:root {
  --ca-overlay-border: #e11d48;
  --ca-overlay-bg: rgb(225 29 72 / 0.12);
  --ca-label-bg: #e11d48;
}

Instances without a preset/theme pick these up automatically — useful for theming a whole docs site in CSS only.

3. Overlay hooks

createAnatomy({
  root,
  overlay: {
    label: true,          // false hides the name chips entirely
    padding: 4,           // inflate every highlight box by 4px
    className: 'glow',    // your own CSS class on every box

    // Custom label text/content per box
    renderLabel: ({ part, element, index }) =>
      part.id === 'tab' ? `${part.name} #${index + 1}` : part.name,

    // Full access to the box element after creation
    decorateOverlay: (box, { part }) => {
      box.style.boxShadow = '0 4px 16px rgb(13 148 136 / .3)';
      if (part.id === 'thumb') box.append(makeCornerBadge());
    },
  },
});
  • renderLabel returns a string (used as text) or a Node (appended). Return null to fall back to the part name.
  • decorateOverlay runs once per box per highlight — keep it cheap; it executes on every hover.

Recipes

Match your brand in one line

createAnatomy({ root, panel, theme: { accent: 'var(--brand-500)' } });

Screenshot-friendly (no animation, no labels)

createAnatomy({ root, theme: { transitionMs: 0 }, overlay: { label: false } });

Dark page

createAnatomy({ root, theme: {
  overlayBg: 'rgb(255 255 255 / 0.08)',
  overlayBorder: '#a5b4fc',
  labelBg: '#e0e7ff', labelFg: '#1e1b4b',
}});