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

2px

Size Token Scale

xs (12px)
sm (16px)
md (20px)
lg (24px)
xl (32px)
2xl (40px)
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
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}
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

PropTypeDefault
namestring
iconLucideIcon | React.ElementType | React.ReactNode
sizeIconSizeToken | number | string"md"
colorIconColorToken | (string & {})"default"
strokeWidthnumber
absoluteStrokeWidthboolean
customSizenumber | string
titlestring
classNamestring
Configure Theme
Theme
Accent Color
Custom
Gray Family
Appearance
Radius
Scaling
Panel Style
Heading Font
Body Font