You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Icon sizes are set per call site with no scale behind them. A sweep of packages/ui/src and apps/desktop/src finds 145 hardcoded size={n} props across 11 distinct values:
size
uses
14
37
16
35
15
27
13
21
12
13
11 / 18 / 20 / 24 / 26 / 28
12 combined
11, 13, 15 and 26 sit on no scale at all — Astryx's Icon offers xsm/sm/md/lg (12/16/20/24), and these fall between its steps. Narrowing to icons passed as a Button/IconButtonicon prop — one position, one visual role — still spreads across 14 (16 uses), 16 (10), 15 (8), 13 (3) and 11 (2). Same slot, five different answers.
A token already exists and is almost unused:
--icon-size:16px; /* chrome glyph size (nav + button icons); dense meta (12-14) and hero (20+) stay call-site */
It has 2 references in the entire codebase, both in plan-mode.css. Its comment defines a real three-tier policy — chrome via token, dense meta at 12–14, hero at 20+ — but nothing enforces the tiers, so call sites drift and the token stays dead.
The precedent for fixing this is in the same file. Stroke width had the same problem (eight values across 143 usages) and was solved with one rule:
svg.lucide { stroke-width:1.75; }
That comment also explains why size cannot be handled identically: a global size rule would capture icons Astryx sizes through its own slot props (Icon's size, SideNavItem's renderIconSlot), which are the component's decision, not the product's. So this needs per-tier tokens plus a sweep, not one blanket rule.
Suggested direction:
Give each tier of the existing policy its own token (chrome / dense-meta / hero) instead of one --icon-size that only names the first.
Sweep the 145 call sites onto the nearest tier, recording anywhere a genuine exception is needed.
Add a check — check-dead-css.mjs and check-a11y.mjs are existing homes for this kind of governance — so new call sites cannot reintroduce off-scale values.
Found while reworking the chat message meta row (#2358), which landed its icons on 14 to match this policy's dense-meta tier. That PR deliberately does not attempt the sweep.
I'm working on this. Icon size={n} is currently a per-call-site choice, including values that sit between Astryx steps. I will give the existing chrome / dense-meta / hero policy its own tokens, sweep the hardcoded sizes onto those tiers, and add a check so off-scale values cannot come back.
The measurements this rests on no longer hold on current main. The --icon-size token no longer exists anywhere in the tree, and hardcoded size={n} props across packages/ui/src and apps/desktop/src are down from 145 uses across 11 values to 23 across 6, largely as a side effect of moving call sites onto Astryx Icon and IconButton (#5134, #4789). What is left looks too small to justify per-tier tokens plus a governance check, so closing. Happy to reopen with a fresh sweep if the drift returns.
Activity
1625567290 commentedon Aug 16, 2026
I'm working on this. Icon
size={n}is currently a per-call-site choice, including values that sit between Astryx steps. I will give the existing chrome / dense-meta / hero policy its own tokens, sweep the hardcoded sizes onto those tiers, and add a check so off-scale values cannot come back.Astro-Han commentedon Sep 17, 2026
The measurements this rests on no longer hold on current
main. The--icon-sizetoken no longer exists anywhere in the tree, and hardcodedsize={n}props acrosspackages/ui/srcandapps/desktop/srcare down from 145 uses across 11 values to 23 across 6, largely as a side effect of moving call sites onto AstryxIconandIconButton(#5134, #4789). What is left looks too small to justify per-tier tokens plus a governance check, so closing. Happy to reopen with a fresh sweep if the drift returns.