Subset Lattice
A Hasse diagram of the power-set lattice over a small set of elements. Renders 2^n nodes laid out in layers by popcount (the "diamond" — 1-3-3-1 for n=3, 1-4-6-4-1 for n=4), joined by edges between subsets that differ by exactly one element.
SubsetLattice is the canonical picture for SOS-DP, set-cover, bitmask-DP, and Travelling-Salesman-on-subsets narratives — anywhere the algorithm walks a subset lattice and the picture wants to read as which subsets are filled and how we got from the empty set to the full one.
Customize
Lattice
4
Overlays
Installation
npx shadcn@latest add https://craftbits.dev/r/subset-lattice.jsonUsage
import { SubsetLattice } from "@craft-bits/core";
<SubsetLattice elements={["a", "b", "c"]} />;Controlled selection on a bitmask:
const [mask, setMask] = useState<number | null>(0b011);
<SubsetLattice
elements={["a", "b", "c"]}
selected={mask}
onSelectedChange={setMask}
/>;Per-subset values plus a glowing optimal path:
const values = new Map<number, number>([
[0b000, 0],
[0b001, 3],
[0b011, 5],
[0b111, 9],
]);
<SubsetLattice
elements={["a", "b", "c"]}
values={values}
optimalPath={[0b000, 0b001, 0b011, 0b111]}
/>;Ghost mode — non-interactive nodes shrink into background scaffolding so the active sub-region pops:
<SubsetLattice
elements={["a", "b", "c", "d"]}
interactiveMasks={[0b0001, 0b0011, 0b0111, 0b1111]}
ghostMode
/>Understanding the component
- Popcount layering. Subsets are bucketed by
popcount(mask)— empty set at the top, full set at the bottom. Within a layer, masks render in numeric order so geometry stays deterministic across renders. - Cover edges only. Two subsets are joined iff one is reachable from the other by adding exactly one element. The lattice is drawn as undirected lines for visual clarity; the upward orientation of the picture conveys the lattice direction.
- Bitmask is the source of truth. The public API is a bitmask. The
selectedSubsetprop is sugar — it resolves to a bitmask viaelements.indexOf, so passing element names you didn't declare is silently dropped. - Controlled + uncontrolled selection. Pass
selected+onSelectedChange(orselectedSubset) for controlled mode (the Radix pattern). PassdefaultSelectedto let the component own the mask internally. - Optimal path glows; everything else dims. When
optimalPathis non-empty, its constituent edges glow at full opacity and width while every other edge dims to a whisper. Drop the prop to render every edge equally. - Ghost mode. With
interactiveMasksset andghostModeenabled, non-interactive nodes shrink and dim. Use this when only a path or sub-lattice matters and the rest is scaffolding. - Element cap.
elements.lengthis clamped to 6 — the diagram tops out at 64 nodes. Beyond that, the lattice stops being readable and a different visualisation is the answer. - Reduced motion.
usePrefersReducedMotion()short-circuits every transition to instant. Node entries, edge draws, and the selected-node sonar pulse all snap into place.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
elements | readonly string[] | required | The ground set indexing every subset. Clamped to at most 6. |
values | ReadonlyMap<number, number | string | null> | — | Per-subset values keyed by bitmask. Filled subsets render the value; others render the set-builder label. |
selected | number | null | — | Controlled selected mask. Pair with onSelectedChange. |
selectedSubset | readonly string[] | null | — | Sugar for selected — resolved via elements.indexOf. |
defaultSelected | number | null | null | Uncontrolled initial mask. |
onSelectedChange | (mask: number) => void | — | Fires when a subset is clicked or activated via keyboard. |
highlightedEdges | readonly [number, number][] | — | Edges to highlight as [fromMask, toMask] pairs. |
optimalPath | readonly number[] | — | Sequence of masks forming an optimal path through the lattice. |
interactiveMasks | readonly number[] | null | null (all interactive) | Restrict which subsets accept clicks. |
ghostMode | boolean | false | Shrink non-interactive nodes into background scaffolding. |
accentHex | string | var(--cb-accent) | Track accent color. Use a #hex to enable drop-shadow glow on the selected node. |
transition | Transition | SPRINGS.smooth | Override the node/edge transition spring. |
className | string | — | Merged onto the outer SVG element. |
Accessibility
- The outer SVG is
role="img"with anaria-labelsummarising the ground set, subset count, and currently selected mask. - Every interactive node carries
role="button",aria-label(subset + value),aria-pressed, andtabIndex={0}. Enter and Space both activate. - Every node's hit target is at least 44 by 44 px (WCAG 2.5.8 AAA), even though the visible circle is smaller.
- Motion respects
prefers-reduced-motion: node entries, edge draws, and the sonar pulse all snap to instant.
Credits
- Extracted from:
algoflashcards(src/lessons/primitives/viz/SubsetLattice.tsx). The original was scoped to a specific DP lesson — it took adpValues: Map, hard-wiredtrackHex, and rendered HTML chrome around the SVG. The library extract generalises toelements: string[](with the bitmask still the canonical key), adds a controlled / uncontrolled selection lever on the Radix pattern, acceptsselectedSubsetas sugar over the bitmask, routes node and edge dimensions throughSVG_TOKENS, and drops every lesson-specific prop.