Iconography
Icons are inlined as stroked SVG, never an icon font.
The probability of an icon font failing to load from a CDN is not small (network policy, sandboxes, offline), and the failure mode is bad: icon-only buttons become empty boxes, or degrade into a substitute glyph that is stylistically wrong. Given how often icons appear, betting on an external dependency is not worth it.
Specification: viewBox="0 0 16 16" (20 for the tips lightbulb); fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round. Colour always comes from the parent's text token — an icon with its own colour is an icon that is wrong in the next state.
Three hit-area steps
Icon-only controls use 24 / 32 / 40, with 32 the default. There is no step below 24. The glyph inside is free to be smaller: a 24px plate and a 32px button both carry a 16px glyph. When a control has to look smaller than its target — a switch track, a slider, an 11px text link — keep the visual size and pad the hit area to 24, with an equal negative margin so the layout does not move.
Three kinds of icon, three obligations
- A decorative icon beside its own text label takes
aria-hiddenso it is not announced twice. - An interactive icon-only button takes an
aria-labeldescribing the action, not the picture ("Zoom in", not "plus"). - An indicative icon carrying state needs screen-reader text, because colour and shape alone convey nothing.
Directional icons — arrows, undo, indent — need a class that RTL can flip. Clocks, checkmarks, play buttons, logos and charts with a time axis must never be flipped. Prefer up/down chevrons where there is a choice: they need no flipping, which is why the property-card disclosure points up and down rather than left and right.