Foundations
Iconography
Comitor uses Lucide React exclusively. The library ships consistent stroke-based icons that align with Inter's clean geometry. lucide-react is a required peer dependency of @comitor/ui — one copy in the bundle, shared by the package and by your app.
Lucide-only policy
All icons across every Comitor product surface must come from lucide-react. No other icon library — no hero-icons, no font-awesome, no custom SVGs in UI copy.
The full Lucide catalogue ships well over 1,500 icons covering every common UI need. If an icon does not exist in Lucide, raise a design system issue before custom-drawing.
Lucide is on v1 — brand icons are gone
The version scale jumped from 0.x to 1.x without changing the icon API, which is why the package declares the peer as >=0.540.0. What v1 did change is the catalogue: the third-party brand and logo icons were removed. Importing one is a build error, not a missing glyph.
| Removed in v1 | Used in this system instead | Why |
|---|---|---|
| Github | GitBranch | A generic repository mark. Reads the same in a nav item and survives the next catalogue change. |
| Figma | Component | Stands for the design-source link without borrowing a third party's logo. |
Some older names survive as deprecated aliases — Loader2 still resolves to LoaderCircle, AlertCircle to CircleAlert. Write the v1 name in new code.
Size grid
12px
Chevrons and status dots inside dense rows
size-314px
Inside small buttons and input group addons
size-3.516px
Default — nav items, labels, everything unmarked
size-420px
Card icons, callout icons
size-524px
Empty states, feature highlights
size-632px
Hero icons, large illustrations
size-8Icon size comes from the spacing scale, not the type scale. That is what lets the text-size axis move icons and labels together: at the large step a size-4 icon grows with the 16px label beside it instead of standing still while the label swells.
Automatic sizing
Twenty-one places across eleven component families carry [&_svg:not([class*='size-'])]:size-4— menu and command rows, Select triggers and items, ItemMedia, InputGroup addons, ButtonGroupText, NavigationMenu links, Toggle, and the Dialog close button. An icon dropped into one of those with no size class of its own renders at 16px, so an explicit size-4 is redundant there, while size-5 genuinely overrides.
Button is deliberately not one of them: it sets a gap and a text size but applies nothing to a child svg, so an icon inside a button keeps Lucide's own default of 24px until you size it. Give it a size-* class, or a size prop when it goes through leftIcon / rightIcon.
Icon colour follows the colour contract
Lucide renders with stroke="currentColor", so an icon takes the text colour of whatever contains it. That makes the three-role contract apply unchanged — and it means the wrong choice is invisible to the compiler.
Passing an icon to a component
Shell components that take an icon — nav items, app descriptors, sidebar entries — accept the component reference rather than a rendered element, so they can apply their own size and colour classes to it.
import type { NavItem } from '@comitor/ui/shell'
import { LayoutDashboard } from 'lucide-react'
// The slot takes the COMPONENT, not an element:
// icon: LayoutDashboard ✓
// icon: <LayoutDashboard /> ✗
const item: NavItem = {
id: 'overview',
label: 'Overview',
href: '/tasks',
icon: LayoutDashboard,
}
// The slot's type is ShellIcon = LucideIcon | ComponentType<{ className?: string }>,
// so a custom SVG wrapper that accepts className fits the same slot.Sample icons — 16px default
Stroke and usage
Do
- Leave the stroke width at Lucide's default of 2 in all product UI.
- Pair icons with a visible text label when used in navigation.
- Give an icon-only control an accessible name —
aria-labelor visually hidden text. - Size icons inside a Button explicitly — 14px in a small button — and let menu rows, addons and Select inherit the automatic 16px.
Don't
- Do not change stroke width — it breaks visual consistency across surfaces.
- Do not use icons as decorative filler without semantic meaning.
- Do not mix Lucide with any other icon library on the same surface.
- Do not colour a meaningful icon with a fill token — it will not clear 3:1.