# Icons Icon stroke weight, sizing, state colors, variants and RTL mirroring. ## Match icon stroke to text weight | Adjacent text | Rendered stroke width | | --- | --- | | Regular (400), 14–16px | `1.5px` | | Medium or semibold (500–600) | `2px` | | Bold (700), or an emphasized standalone icon | `2.5px` | The widths are rendered pixels. A 24px-grid icon drawn at 16px scales its stroke by 16/24, so `stroke-width="2"` paints about `1.33px`. Use the library's absolute-stroke option, such as Lucide's `absoluteStrokeWidth`, or set `vector-effect: non-scaling-stroke` on the SVG's shapes. ```tsx // Good: stroke tuned to the semibold label // Bad: 1.5px stroke against a bold label ``` - **One library per surface.** Never mix icon libraries on one toolbar. Where the library has no stroke variants, keep its native stroke and use size or color for emphasis. - **Size inline icons at `1em`–`1.25em`** of the adjacent font size, so the pair scales together. ## One SVG, recolored per state Draw every icon with `currentColor` and let CSS state drive the color. Strip hardcoded fills such as `fill="#666"` to `currentColor` when importing icons. ```html … ``` ```css /* Use the project's color tokens */ .icon-button { color: var(--icon-muted); } .icon-button:hover { color: var(--icon-strong); } .icon-button[aria-pressed="true"] { color: var(--icon-active); } .icon-button:disabled { opacity: 0.4; } ``` ```html ``` ## Outline default, fill active Where an icon set offers outline and filled variants, use them as a state pair, never interchangeably: | Variant | Use for | | --- | --- | | Outline | Default state in toolbars, list rows and inline text | | Fill | Selected or active state, such as the active tab, a toggled bookmark or a liked heart | ```tsx // Good: variant communicates state // Bad: filled everywhere, so the active tab has no state signal ``` Cross-fade the swap with the values in [icon-transitions.md](icon-transitions.md) only where the change is infrequent, such as a bookmark or a like. An active tab swaps instantly. ## Design at render size - Test every icon at the smallest size it renders, often `16px`. It must stay recognizable there. - Prefer a simplified glyph for small contexts over scaling down detailed artwork. - Where the set ships per-size grids such as `16`, `20` and `24`, use the grid that matches the render size. A 24px drawing scaled to 16px lands off the pixel grid and renders soft. - Always SVG, never raster. ## Icons in RTL Under `dir="rtl"`, flip icons whose meaning is tied to reading direction, and leave the rest alone: | Flip | Don't flip | | --- | --- | | Back and forward arrows, navigation chevrons | Logos and brand marks | | Text-block glyphs for alignment, lists and indent | Checkmarks | | Speaker and volume waves | Physical objects such as clocks, cups and pencils | | Directional glyphs such as "send" | Media playback, which stays LTR by convention | Use one mechanism per element. Two flips on one icon can compound back to unflipped. ```css [dir="rtl"] .icon-directional { scale: -1 1; } ``` ```tsx // Tailwind ``` Analyze composite icons part by part. A badge or slash overlay may keep its position while the base glyph flips. Accessible names for icon-only buttons belong to `better-accessibility`.