ADR-011: Variants & Composition
Decision
Add a prop variant for tone, size, or density changes; create a new component only when the semantic role, keyboard model, or data model differs. Compose multi-part components with array args for homogeneous content and compound sub-components for heterogeneous content.
Key rules
- New component when the semantic role differs, the keyboard model differs, or the data model differs.
- Prop variant when only tone (
info/success/etc.), size, or density changes — never a near-duplicate component for cosmetic differences. Use CVA variants. - When in doubt: if the same ARIA role applies, it is a variant, not a new component.
- Document interaction families together in a shared story file so variants can be compared.
- Pattern A (array args): use when all children are the same type, e.g.
<Tabs items={[...]} />. - Pattern B (compound): use when children have different structures, e.g.
<Dialog>+<Dialog.Header>+<Dialog.Body>. - Choose the composition pattern by content heterogeneity, not personal preference.
- Sub-components are attached via
Object.assign(Parent, { Header, Body, Footer })— never exported separately. - Consumers use
<Parent.SubComponent>syntax — never import a sub-component directly.
Code patterns
// Pattern B — compound via Object.assignconst Dialog = Object.assign(DialogRoot, { Header: DialogHeader, Body: DialogBody, Footer: DialogFooter,});Why
A single ARIA role spanning several visual treatments signals one component with variants, not many components; collapsing cosmetic differences into CVA variants keeps the surface area small and the keyboard and accessibility contracts consistent. Splitting only on semantic role, keyboard model, or data model draws the boundary where it actually matters. Choosing composition by content shape — array args for homogeneous lists, compound sub-components for heterogeneous sections — keeps each API as simple as the content it carries. This record consolidates ADR-011 (compound components) into ADR-011 and supersedes it; the Object.assign compound pattern is retained unchanged as current dmwd-io practice.
Applies when
You are deciding whether to add a variant prop or split into a separate component, or designing the API for a component that has multiple distinct sections or sub-parts.
Related
- ADR-009 — icon role, placement, and layout (a role-named-prop API surface).
- ADR-003 — typography and density (the density variant scale).