Skip to content

ADR-009: Icon Role, Placement, and Layout

Decision

Icons are expressed through role-named API props, and every icon-beside-text row is laid out as a two- or three-column CSS grid. Content never stacks below an icon.

Key rules

  • Use role-named props: leadingIcon, trailingIcon, triggerIcon, endAdornment. Use a generic iconPlacement?: "start" | "end" only when the role does not change between positions.
  • Built-in affordances (chevrons, clear buttons, loading spinners) are owned by the component, not passed as props.
  • Decorative icons are aria-hidden="true"; meaningful icons carry a visible label or an aria-label.
  • Two-column layout: grid grid-cols-[auto_1fr] (icon + content). Three-column: grid grid-cols-[auto_1fr_auto] (icon + content + action).
  • Always items-start; offset the icon with mt-0.5 for optical alignment; the icon is shrink-0.
  • Never flex-wrap on an icon row. Action buttons go in the rightmost auto column — never as a block sibling below the content.
  • Applies to print as well as screen (legal rows, exhibit tables, checklist items).

Code patterns

{/* Two-column: icon + content */}
<div className="grid grid-cols-[auto_1fr] items-start gap-4">
<Icon className="mt-0.5 size-5 shrink-0 text-muted-foreground" aria-hidden="true" />
<div className="flex flex-col gap-1"></div>
</div>
{/* Three-column: icon + content + action */}
<div className="grid grid-cols-[auto_1fr_auto] items-start gap-4">
<Icon className="mt-0.5 size-5 shrink-0 text-muted-foreground" aria-hidden="true" />
<div className="flex flex-col gap-1"></div>
<Button variant="outline" size="sm">Open preview</Button>
</div>

Why

Content stacking below an icon is the single most common layout bug in the system; a CSS grid makes the icon-beside-content invariant structural rather than incidental. Role-named props keep the icon’s meaning explicit at the call site. Decorative-versus-meaningful handling satisfies WCAG 2.2 SC 1.1.1.

Applies when

You are adding an icon to any component, designing an icon API, or reviewing a layout where content stacks below an icon or an action button lands in the wrong place.

  • ADR-008 — border, surface & overlay discipline.
  • ADR-007 — print-friendly components (the grid survives @media print).