|Kit

ThemeIcon

Polymorphic

Square, 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, focus ring, 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/ui-react/theme-icon';
import { Search } from 'lucide-react';

<ThemeIcon color="gray" 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

SpinnerLoading preview

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="gray" 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 — for the common "icon-only trigger" case, reach for ActionIcon instead, which adds the accessibility wiring (aria-label, focus/disabled states) that a real trigger needs.

import Link from 'next/link';
import { User } from 'lucide-react';

<ThemeIcon asChild variant="subtle" color="gray">
  <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 ThemeIcon for a decorative themed icon glyph — nothing to click, nothing to focus.
  • Reach for ActionIcon when the icon is an interactive trigger — it adds aria-label requirements, focus/disabled states, and loading support that ThemeIcon intentionally omits.
  • Reach for Badge for an inline status chip or counter — ThemeIcon is a square, icon-first display, not a text label.

On this page