Icon
Universal vector icon renderer with strict size tokens (xs to 3xl), numeric pixel scaling, semantic color tokens, and open SVG component wrapping.
// Plain markup
import { Icon } from "@shavin/ui";Interactive Playground
xl2px stroke
<Icon name="clock" size="xl" color="accent" strokeWidth={2} />Icon Name
Size Token
Color
Stroke Width
2pxSize Token Scale
xs (12px)
sm (16px)
md (20px)
lg (24px)
xl (32px)
2xl (40px)
Component Source
import { Icon } from "@shavin/ui";
<Icon name="Sparkles" size="xs" color="accent" />
<Icon name="Sparkles" size="sm" color="accent" />
<Icon name="Sparkles" size="md" color="accent" />
<Icon name="Sparkles" size="lg" color="accent" />
<Icon name="Sparkles" size="xl" color="accent" />
<Icon name="Sparkles" size="2xl" color="accent" />Semantic Color Tokens
default
subtle
accent
contrast
success
warning
danger
Component Source
import { Icon } from "@shavin/ui";
<Icon name="Shield" color="default" />
<Icon name="Shield" color="subtle" />
<Icon name="Shield" color="accent" />
<Icon name="Shield" color="contrast" />
<Icon name="Shield" color="success" />
<Icon name="Shield" color="warning" />
<Icon name="Shield" color="danger" />Direct Component Passing vs Name String
name="Zap"
icon={Heart}
Component Source
import { Icon } from "@shavin/ui";
import { Zap, Heart } from "lucide-react";
// 1. By string name (dynamic lookups in builder & schema)
<Icon name="Zap" size="lg" color="warning" />
// 2. Direct component import (tree-shakeable in app code)
<Icon icon={Heart} size="lg" color="danger" />Custom & Native SVG Support
While @shavin/ui includes the full Lucide catalog by default, the <Icon /> primitive is completely open and accepts any custom vector graphic, inline SVG, or 3rd-party icon component (such as Radix Icons, Phosphor, FontAwesome, or custom company brandmarks).
1. Direct Custom Component Passing
Pass your custom React SVG component directly into the icon prop. It automatically inherits all size tokens, semantic colors, and accessibility attributes:
import { Icon } from "@shavin/ui";
import { MyCustomBrandmark } from "./MyCustomBrandmark";
export function Header() {
return (
<Icon
icon={MyCustomBrandmark}
size="xl"
color="accent"
aria-label="Company Brandmark"
/>
);
}2. Inline SVG Node Wrapping
You can also pass raw JSX SVG elements directly. <Icon /> wraps them cleanly with token classes and dimensional bounding:
import { Icon } from "@shavin/ui";
<Icon size="2xl" color="contrast">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2L2 22h20L12 2z" />
</svg>
</Icon>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | — | Name of the icon in Lucide / Shavin icon set (e.g. "Sparkles", "Search", "arrow-right"). |
| icon | LucideIcon | React.ElementType | React.ReactNode | — | Direct icon component or custom React node to render. |
| size | IconSizeToken | number | string | "md" | Size token (xs, sm, md, lg, xl, 2xl, 3xl) or custom numeric pixel value (16-256) or CSS size string. |
| color | IconColorToken | (string & {}) | "inherit" | Semantic color token or custom hex/CSS color string. Defaults to "inherit" (currentColor), so an icon always takes the colour of its parent (buttons, tabs, chips, filled accent surfaces). |
| strokeWidth | number | 2) | Stroke width for vector lines (from 0.5 to 3.0 in 0.25 steps, default 2). |
| absoluteStrokeWidth | boolean | — | Whether stroke width remains absolute regardless of scaling. |
| customSize | number | string | — | Custom pixel or CSS size override if not using size prop. |
| title | string | — | Optional title for accessibility hover tooltip. |
| className | string | — | — |