ThemeIcon
PolymorphicSquare, non-interactive icon-display box. A muted, low-saturation surface that reads as decoration, not as a control.
ThemeIcon is a decorative, non-interactive icon glyph — the same size/radius scales as ActionIcon, but a deliberately different look. It renders a plain div (no disabled, loading, or click handling), and every variant is a muted surface: just enough contrast to sit above the page, never a vivid CTA-style fill. Reach for it wherever a themed icon glyph decorates content: feature callouts, list-item glyphs, empty states.
import { ThemeIcon } from "@42-central/ui-react/theme-icon";
import { Search } from "lucide-react";
<ThemeIcon color="neutral" variant="filled" radius="lg">
<Search />
</ThemeIcon>;The icon is auto-sized by the parent's size variant — drop in a bare lucide-react icon and you'll never need to set size={n} on it.
Playground
Component
Dir
Presets
Props
Code
<Component variant="default" size="md" />Variants
Five muted surfaces — none of them read as a button. filled is a tinted surface with a border a shade darker, for a raised card feel; light is the same tint without the border; outline and subtle stay progressively quieter.
Code
import { Star } from 'lucide-react';
<ThemeIcon variant="filled"><Star /></ThemeIcon>
<ThemeIcon variant="light"><Star /></ThemeIcon>
<ThemeIcon variant="outline"><Star /></ThemeIcon>
<ThemeIcon variant="subtle"><Star /></ThemeIcon>
<ThemeIcon variant="default"><Star /></ThemeIcon>Colors
Every variant (except default) accepts any color from the shared palette.
Code
<ThemeIcon variant="filled" color="neutral" radius="lg"><Search /></ThemeIcon>
<ThemeIcon variant="filled" color="brand"><Heart /></ThemeIcon>
<ThemeIcon variant="light" color="blue"><Star /></ThemeIcon>
<ThemeIcon variant="outline" color="teal"><Settings /></ThemeIcon>
<ThemeIcon variant="filled" color="red"><Trash2 /></ThemeIcon>Sizes
Five sizes from xs to xl — identical footprint to ActionIcon at the same size, so the two drop into the same layouts without a visual mismatch.
Code
<ThemeIcon size="xs"><Star /></ThemeIcon>
<ThemeIcon size="sm"><Star /></ThemeIcon>
<ThemeIcon size="md"><Star /></ThemeIcon>
<ThemeIcon size="lg"><Star /></ThemeIcon>
<ThemeIcon size="xl"><Star /></ThemeIcon>Radius
Independent radius scale, including full for circular glyphs.
Code
<ThemeIcon radius="xs"><Star /></ThemeIcon>
<ThemeIcon radius="sm"><Star /></ThemeIcon>
<ThemeIcon radius="md"><Star /></ThemeIcon>
<ThemeIcon radius="lg"><Star /></ThemeIcon>
<ThemeIcon radius="xl"><Star /></ThemeIcon>
<ThemeIcon radius="full"><Star /></ThemeIcon>Polymorphic with asChild
Same Ark UI polymorphism as ActionIcon. Wrap a link when the icon itself needs to be clickable — the kit's focus ring comes along, so the composed element is keyboard-visible. For the common "icon-only trigger" case, reach for ActionIcon instead, which adds the rest of the wiring (aria-label requirements, disabled and loading states) that a real trigger needs.
import Link from "next/link";
import { User } from "lucide-react";
<ThemeIcon asChild variant="subtle" color="neutral">
<Link href="/profile" aria-label="Open profile">
<User />
</Link>
</ThemeIcon>;API
Prop
Type
All other props are forwarded to the underlying div (or asChild element).
When to use which
- Reach for
ThemeIconfor a decorative themed icon glyph — nothing to click. Composed onto a link withasChildit still focuses correctly. - Reach for
ActionIconwhen the icon is an interactive trigger — it addsaria-labelrequirements, disabled states, and loading support thatThemeIconintentionally omits. - Reach for
Badgefor an inline status chip or counter —ThemeIconis a square, icon-first display, not a text label.
Changelog
- #316
The
defaultThemeIcon and thefilledTabs and SegmentGroup tray use the kit's hairline border and quiet fill instead of the gray scale
- #142
Carry the kit's focus ring, so composing one onto a real control with
asChildis keyboard-visible
- #11
New
ThemeIcon: a square, non-interactive icon box