@memoir/tree
Memoir Labs

Design

Style @memoir/tree with CSS variables, stable selectors, and custom cards.

@memoir/tree ships one small stylesheet. It sets the Memoir look: warm canvas, light cards, sharp corners, black outlines, black shadows, and root-node focus styling.

Import Styles

import "@memoir/tree/styles.css";

The package never auto-imports CSS. Consumers opt in explicitly.

Theme

Use theme only to pick a built-in preset:

<FamilyTree people={people} subject="alex" relationships={relationships} theme="system" />
  • memoir: the default cream canvas and outlined cards.
  • system: neutral system colors.

For custom colors, use CSS variables through className or style.

The package also exports treeStylePresets and getTreeStyleName(theme) for wrappers that need to inspect or normalize preset names.

CSS Variables

<FamilyTree
  className="my-tree"
  people={people}
  subject="alex"
  relationships={relationships}
/>
.my-tree {
  --tree-canvas-bg: #fff7df;
  --tree-card-bg: #ffffff;
  --tree-card-border: #17120f;
  --tree-card-shadow: 5px 5px 0 #17120f;
  --tree-edge: #17120f;
  --tree-edge-width: 2;
}

Useful variables:

  • --tree-surface-bg
  • --tree-canvas-bg
  • --tree-card-bg
  • --tree-card-fg
  • --tree-card-border
  • --tree-card-shadow
  • --tree-card-radius
  • --tree-edge
  • --tree-edge-width
  • --tree-muted-fg

Styled Family Card

Use StyledFamilyCard when you want a quick configurable card without writing custom markup:

import { FamilyTree, StyledFamilyCard } from "@memoir/tree";

<FamilyTree
  card={StyledFamilyCard}
  cardProps={{
    radius: "round",
    outlined: true,
    shadow: "flat",
    avatar: "round",
  }}
  people={people}
  subject="alex"
  relationships={relationships}
/>

radius accepts square, soft, round, pill, or any CSS radius value. shadow accepts none, flat, soft, or any CSS shadow value. avatar accepts auto, hidden, square, soft, or round.

Stable Selectors

Shared selectors:

  • [data-tree-surface]
  • [data-tree-canvas]
  • [data-tree-card]
  • [data-tree-edge]
  • [data-person-id]
  • [data-selected]
  • [data-focused]

Family selectors:

  • [data-family-tree]
  • [data-family-canvas]
  • [data-family-card]
  • [data-family-edge]
  • [data-relation]
  • [data-generation]
  • [data-side]

Org selectors:

  • [data-org-chart]
  • [data-org-card]
  • [data-org-edge]
  • [data-depth]
  • [data-parent-id]
[data-family-card][data-relation="self"] {
  background: var(--tree-accent);
}

[data-family-edge][data-edge-kind="adoptive"],
[data-family-edge][data-edge-kind="guardian"],
[data-family-edge][data-edge-status="former"] {
  stroke-dasharray: 4 4;
}

Family edge kinds come from the modeled relationship. The default family renderer passes a dashed stroke for adoptive, guardian, and former edges. Other kinds and statuses are still exposed through edge data attributes for custom CSS.

Card Root

Custom cards should spread the provided props onto the card root:

function ProfileCard({ focused, person, relation, ...rootProps }: FamilyCardProps<Person>) {
  return (
    <article {...rootProps}>
      <strong>{person.name}</strong>
      <small>{relation.label}</small>
    </article>
  );
}

Those props carry accessibility metadata, click handlers, keyboard handlers, and styling hooks.

Interaction Hooks

The default interactionMode is "pan", so users can drag the canvas and non-interactive card surfaces with mouse, touch, or pen. Use "pan-page-scroll" when mouse or horizontal touch should drag the tree and vertical touch should scroll the page. Native controls inside cards keep their own pointer behavior. Add data-tree-drag-ignore to any custom card element that should not start panning.

On this page