FamilyTree
Render a subject-centered family neighborhood from app-owned person data.
FamilyTree renders a subject-centered family neighborhood from app-owned person data and plain relationship facts.
Props
type FamilyTreeProps<Person> = {
subject: string;
people: Record<string, Person>;
relationships: FamilyRelationship[];
card?: React.ComponentType<FamilyCardProps<Person>>;
className?: string;
style?: React.CSSProperties;
cardClassName?: string;
edgeClassName?: string;
interactionMode?: "pan" | "scroll" | "none";
onPersonClick?: (person: Person, personId: string) => void;
};The library does not require name, avatarUrl, profile fields, or nested relationship arrays. It only needs stable person IDs.
By default, FamilyTree is self-contained: it fills the parent width, inherits parent height when one exists, falls back to a usable minimum height, clips overflow, and lets users drag-pan the tree horizontally and vertically. Host apps should only pass style, className, or interactionMode when they want to override those defaults.
Relationship Facts
import { rel } from "@memoir/tree";
const relationships = [
rel.parents("alex", ["morgan", "casey"]),
rel.partner("alex", "jordan", { relation: "spouse" }),
rel.children(["alex", "jordan"], ["riley", "quinn"]),
rel.guardians("riley", ["morgan"]),
];The helpers produce plain rows:
parentage: parent/child facts.partnership: spouse, partner, or coparent facts.guardianship: guardian/child facts.
Card Contract
If you omit card, FamilyTree uses DefaultFamilyCard, which displays name, label, profile.display, or the person ID.
Your custom card receives the person object and computed relation metadata:
import type { FamilyCardProps } from "@memoir/tree";
function PersonCard({ person, relation, selected, ...props }: FamilyCardProps<Person>) {
return (
<article {...props}>
<strong>{person.profile.display}</strong>
<small>{relation.label}</small>
{selected ? <span>Selected</span> : null}
</article>
);
}Computed relation labels include self, parent, grandparent, child, grandchild, sibling, half-sibling, partner, coparent, guardian, and unknown.
Layout
The default layout shows a subject-centered family window:
- generation
-2: grandparents - generation
-1: parents and guardians - generation
0: siblings, half-siblings, subject, partners, coparents - generation
1: children - generation
2: grandchildren
Cards are measured with ResizeObserver. The first pass uses a fallback size, then layout recalculates with the actual rendered card dimensions.
The root element owns the viewport behavior. interactionMode="pan" uses a clipped drag-panning viewport, interactionMode="scroll" exposes native scrollbars, and interactionMode="none" clips without user navigation.
Styling Hooks
FamilyTree emits stable attributes:
data-family-treedata-family-canvasdata-family-card-positionerdata-family-measuredata-family-carddata-family-person-iddata-relationdata-selecteddata-family-edge