@memoir/tree
Memoir Labs

Getting Started

Install @memoir/tree and render your first family tree or org chart.

@memoir/tree is a lightweight React renderer for family trees and org charts. Your app owns the data model, permissions, routes, editing flows, and card markup. The package handles measured layout, spouse-aware family grouping, SVG edges, pan/scroll viewport state, accessibility props, and a small CSS-variable skin.

Install

bun add @memoir/tree

Requires React 19. Import the stylesheet once when you want the default Memoir look:

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

Family Tree

Graph mode is the best starting point for app code. It is just JSON-shaped state: people, a subject, partnership groups, and parent-child links.

import { FamilyTree, type FamilyGraph } from "@memoir/tree";
import "@memoir/tree/styles.css";

type Person = {
  id: string;
  name: string;
};

const graph: FamilyGraph<Person> = {
  people: {
    alex: { id: "alex", name: "Alex" },
    jordan: { id: "jordan", name: "Jordan" },
    riley: { id: "riley", name: "Riley" },
  },
  subject: "riley",
  partnershipGroups: [
    { id: "alex-jordan", partners: ["alex", "jordan"], relation: "spouse" },
  ],
  parentChildLinks: [
    { id: "alex-riley", groupId: "alex-jordan", parentId: "alex", childId: "riley" },
    { id: "jordan-riley", groupId: "alex-jordan", parentId: "jordan", childId: "riley" },
  ],
};

export function Page() {
  return <FamilyTree graph={graph} />;
}

To add someone, update the same graph state and let React re-render:

const childId = crypto.randomUUID();

setGraph((current) => ({
  ...current,
  people: {
    ...current.people,
    [childId]: { id: childId, name: "New child" },
  },
  parentChildLinks: [
    ...current.parentChildLinks,
    { id: `alex-${childId}`, groupId: "alex-jordan", parentId: "alex", childId },
    { id: `jordan-${childId}`, groupId: "alex-jordan", parentId: "jordan", childId },
  ],
}));

Links with the same groupId attach children to the correct union. Stable IDs make JSON diffs and re-renders predictable.

Org Chart

import { OrgChart, org } from "@memoir/tree";
import "@memoir/tree/styles.css";

const people = {
  ceo: { id: "ceo", name: "Casey", title: "CEO" },
  eng: { id: "eng", name: "Morgan", title: "VP Engineering" },
  design: { id: "design", name: "Riley", title: "Design Lead" },
};

const relationships = [
  org.manager("ceo", ["eng", "design"]),
];

export function Page() {
  return <OrgChart people={people} root="ceo" relationships={relationships} />;
}

Defaults

Family trees and org charts use compact default spacing:

{ row: 80, column: 24, padding: 24 }

Pass spacing when your custom cards need a different density. The default interactionMode is "pan"; users can drag the canvas or 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. Buttons, links, inputs, selects, textareas, contenteditable elements, and elements marked with data-tree-drag-ignore keep their own pointer behavior.

Next

  • FamilyTree: graph mode, adding relatives, multiple unions, lineage, guardianship, and family options.
  • Org Chart: manager/report facts, custom cards, depth limits, and selection.
  • Design: stylesheet import, CSS variables, themes, and stable selectors.
  • Integration: app-owned data, editing flows, and practical checks.
  • API: compact export and prop reference.

On this page