docs: make Icon the canonical icon entrypoint (actions B17) - #2627
Merged
Conversation
🎩 PreviewA preview build has been created at: |
This was referenced Aug 13, 2026
camielvs
commented
Aug 13, 2026
morgan-wowk
approved these changes
Aug 17, 2026
morgan-wowk
left a comment
There was a problem hiding this comment.
🤖 Agent review. Agent-instruction markdown only (canon-registry.md, ui-primitives SKILL.md); no runtime/build surface. Spot-checked docs against icon.tsx — size scale and the !important caveat are accurate. LGTM.
Collaborator
Author
Adds an `icon-usage` entry to the gardening canon-registry so the `consistency` pillar can migrate the 30 files that still import `lucide-react` directly, and fills in the one-line `ui-primitives#icons` rule the entry cites. `Icon` only accepts Lucide names, so brand and language logos from `react-icons`, the shadcn primitives under `src/components/ui`, and raw `<svg>` that is not an icon are recorded as exceptions to keep rather than deviations to migrate. Migration is size-sensitive: `iconVariants` emits `!w-* !h-*` with `!important` and `twMerge` does not dedupe that against a later `size-*`, so a bare swap silently resizes the glyph. The entry marks only on-scale sizes as auto-appliable and flags off-scale and computed classNames for a human. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"or the w-*/h-* pair" read as satisfied by either one alone, which would let an automated run swap <ChevronRight className="w-4" /> — that renders 16x24 today (width from the class, height from Lucide's own attribute), so any size prop changes it. Splits it into its own flag bucket. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
camielvs
force-pushed
the
canon-registry/icon-usage
branch
from
August 17, 2026 22:44
c1b555b to
29788cc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Actions B17 in the gardening queue (#2626): blesses
Iconas the canonical way to render an icon, sothe
consistencypillar is allowed to migrate the stragglers instead of only proposing.Two files, docs only. No
srcchanges — the migration itself is a later, reviewable PR.Why it needed a human
The empirical bar was already met — 222 files import
Icon, 30 still importlucide-reactdirectly (88.1%, over
supermajorityRatio: 0.75), and 10 of the 30 do both, which reads as driftrather than intent. But
pillars/consistency.mdforbids migrating on measurement alone: without aregistry entry that would be the bot inventing a convention and enforcing it repo-wide. Hence the entry.
Non-Lucide icons are exceptions, not stragglers
Icon'snameiskeyof typeof iconsfromlucide-react, so it structurally cannot render anythingelse. Recorded as KEEP so no future run "fixes" them:
react-iconsbrand/language logos —FaPython×2,SiGnubash,SiRuby,TbBrandJavascript,FaGoogleDriveacross 3 files. Lucide dropped brand logos; there is no equivalent to migrate to.src/components/ui/**— 9 files. shadcn primitives (dialog,select,sheet,command,calendar,checkbox,breadcrumb,date-picker) import their own glyphs and are CLI-regenerable, soa hand edit is overwritten by the next
shadcn add.icon.tsxis the primitive.<svg>that isn't an icon —<defs>/<marker>arrowheads inFlowCanvas/Edges/*, theSpinnerprimitive's own markup, and the bespoke resize grip inFloatingWindow.tsx.The swap is not size-neutral, so the entry is not blanket
apply: yesWorth reading before approving, because it contradicts the "mechanical swap" framing in #2623:
iconVariantsemits!w-4 !h-4. Leading-!still compiles to!importantin Tailwind v4.3.3(verified by compiling
!w-4with the project's own Tailwind:.\!w-4 { width: …; !important }), andtwMerge@3.6.0does not dedupe!w-4against a latersize-5— it emits both, so!importantwins.A blind
<ChevronRight className="size-5" />→<Icon name="ChevronRight" className="size-5" />renders16px instead of 20px.
Across the 30 files there are 59 Lucide JSX usages:
size-4,w-5 h-5, …)apply: yes— size moves to thesizepropapply: yesassize="xl"— Lucide's own default iswidth: 24(lucide-react.js:39), sosize="md"would shrink themw-2 h-2×6,h-8 w-8,w-12 h-12)apply: flag— no variant matches andclassNamecan't beat!importantclassName={cn(…)}apply: flag— size not statically readableSo ~46 of 59 usages are provably size-identical; the other 13 need a human. The off-scale ones are mostly
StatusIndicator.tsxatw-2 h-2(8px, belowxs) — if you'd rather they migrate too, theIconscaleneeds a step, which is a primitive change and deliberately not in this PR.
Also fixes a claim I got wrong
#2623 said there was "no
canon-registry.mdentry and no convention-skill rule namingIconascanonical." The registry entry was indeed missing; the convention rule was not —
ui-primitives#iconsalready said "Use
Iconfrom@/components/ui/icon". That line was one sentence with nosizeguidance,which is how the
!importantinteraction went unnoticed, so this PR fills it in: the size scale, thewarning that a size
classNameloses to the variant, and thereact-iconsescape hatch.Checks
prettier --checkpasses on both files. Nosrc, test, or config changes, solint/typecheck/testare unaffected — I did not run the full
validate:testgate because itsfixstep rewrites the workingtree, and there is no code here for it to validate.