Components / Icon

Icon

Lucide icons rendered server-side via lucide-static. No client JS, currentColor-tinted, size + stroke-width tokens.

Section: Components

<Icon /> wraps a Lucide SVG via lucide-static. The SVG string is inlined at build time (no React, no client runtime), tinted with currentColor, and sized with a small token scale. Kebab-case names match Lucide's icon catalog directly — see lucide.dev/icons.

Live grid

Twenty common icons at three sizes. Hover any cell to see the name.

search
chevron-right
chevron-left
chevron-down
x
check
info
alert-triangle
alert-circle
check-circle
arrow-right
arrow-left
arrow-up-right
mail
external-link
copy
key
sparkles
shield
menu
grid.astro | astro
<!-- Three sizes side-by-side for a single name -->
<Icon name="search" size="sm" aria-label="search" />
<Icon name="search" size="md" aria-label="search" />
<Icon name="search" size="lg" aria-label="search" />

Sizes

Five named sizes; pass a number for anything custom.

xs · 12
sm · 16
md · 20
lg · 24
xl · 32
sizes.astro | astro
<Icon name="sparkles" size="xs" />  {/* 12px */}
<Icon name="sparkles" size="sm" />  {/* 16px */}
<Icon name="sparkles" size="md" />  {/* 20px (default) */}
<Icon name="sparkles" size="lg" />  {/* 24px */}
<Icon name="sparkles" size="xl" />  {/* 32px */}
<Icon name="sparkles" size={28} />  {/* arbitrary px */}

Stroke weights

Lucide icons are stroked, so weight = stroke-width.

1
1.5
2 (default)
2.5
weights.astro | astro
<Icon name="chevron-right" size="lg" weight={1} />
<Icon name="chevron-right" size="lg" weight={1.5} />
<Icon name="chevron-right" size="lg" weight={2} />    {/* default */}
<Icon name="chevron-right" size="lg" weight={2.5} />

Anatomy

Property Behavior
Wrapper Inline `<span>` carrying size / class / aria attributes.
SVG Inlined at build time via lucide-static. `currentColor` for stroke, no fills.
Stroke Width set via `weight` prop; line-caps + joins are round (Lucide defaults).

Do / Don't

Property Do Don't
Naming Use kebab-case lucide names verbatim (e.g. "chevron-right"). Invent custom names — they will silently render an empty span.
aria-label Pass `aria-label` for icon-only buttons; pair with visible text when text exists. Use `aria-label` AND surrounding visible text — SR reads both, doubles up.
Sizing Pick a token size ("sm"/"md"/"lg") that matches surrounding text size. Hardcode arbitrary pixel sizes when a token fits — drifts off the scale.
Color Set `color` on the parent — Icon picks it up via `currentColor`. Use SVG `fill` overrides — Lucide icons are stroked, not filled.
Weight Stick with weight 2 (default); use 1.5 for marketing surfaces, never below 1. Mix weights randomly in a single UI — pick one per surface.
Decorative use Omit `aria-label` for purely decorative icons — they get `aria-hidden` automatically. Set `aria-label=""` — empty labels are an accessibility footgun.

Props

Property Type Notes Default
name string (kebab-case lucide name) — required "search", "chevron-right" -
size "xs" | "sm" | "md" | "lg" | "xl" | number 12 / 16 / 20 / 24 / 32 px "md"
weight 1 | 1.5 | 2 | 2.5 maps to SVG stroke-width 2
class string extra classes merged onto the span -
aria-label string (optional) when present, role="img" + aria-label; otherwise aria-hidden -

Usage

Example.astro | astro
---
import Icon from '@/components/ui/Icon.astro';
---

<!-- decorative (default: aria-hidden) -->
<Icon name="chevron-right" />

<!-- with semantic label (announced by screen readers) -->
<Icon name="alert-triangle" size="lg" aria-label="Warning" />

<!-- explicit size + lighter stroke -->
<Icon name="sparkles" size={28} weight={1.5} class="text-violet-400" />

Accessibility

  • Without aria-label, the icon receives aria-hidden="true" — use this for icons paired with visible text.
  • With aria-label, the icon gets role="img" and is announced by screen readers — use this for icon-only buttons or status indicators.
  • Never set both aria-label AND surrounding visible text — pick one or the other.
  • Icons inherit currentColor, so colour them by setting color on the parent.

Source

src/components/ui/Icon.astro — backed by lucide-static.