Iconography
Lucide icons on a 24px grid, sized with the text they sit beside and colored by the component that holds them.
prfct uses Lucide, an open-source set of more than 1,500 consistent, 24px-grid outline icons. Components size and color icons for you; your job is to choose the right one — or none.
import { SearchIcon } from "lucide-react"
const pairs = [
{ size: 14, text: "text-xs", label: "12px text" },
{ size: 16, text: "text-sm", label: "14px text" },
{ size: 18, text: "text-base", label: "16px text" },
{ size: 20, text: "text-lg", label: "18px text" },
{ size: 24, text: "text-2xl", label: "24px text" },
]
export default function IconSizes() {
return (
<div className="flex flex-col gap-4">
{pairs.map(({ size, text, label }) => (
<div key={size} className="flex items-center gap-4">
<span className="w-12 font-mono text-[0.6875rem] text-muted-foreground">
{size}px
</span>
<span className={`flex items-center gap-2 ${text} text-foreground`}>
<SearchIcon
style={{ width: size, height: size }}
aria-hidden="true"
/>
Search
</span>
<span className="font-mono text-[0.6875rem] text-muted-foreground">
{label}
</span>
</div>
))}
</div>
)
}Sizing
Icons are sized to the text they accompany, not to a fixed size. The stroke scales with the icon, so a 16px icon beside 14px text has the same visual weight as the letters.
Small and default badges are the one exception: their icons are 12px, close to the size of the text, so they fit an 18–20px pill.
Inside prfct components, don't size icons yourself. Buttons, menu items, inputs and badges size their icons with [&_svg] selectors. In buttons, menu items and inputs a size-* class on the icon overrides that choice, so add one only when you mean to leave the scale; badges ignore it.
// Correct — the button sizes and spaces the icon
<Button>
<PlusIcon data-icon="inline-start" />
New project
</Button>Color
Icons inherit currentColor. Inside menus and inputs they default to muted-foreground and switch to foreground when the item is highlighted, so the label always leads. Status icons use their status step 11.
Guidelines
- Pair icons with text. Icons alone are ambiguous. Use icon-only buttons only for universally understood actions (close, search, more) and always give them an
aria-labeland a tooltip. - One metaphor per action. Use the same icon for the same action everywhere:
Trash2always means delete. - Decorative icons are hidden. Icons next to a text label are decorative; Lucide renders
aria-hidden="true"by default. - Don't mix icon families. Mixed stroke widths and corner styles look accidental. If you need a brand mark Lucide doesn't have, draw it on the same 24px grid with a 2px stroke.