Skip to main content

Icon Tile

A consistent square surface for an icon, initials or a short label.

1import {
2 CreditCardIcon,
3 Folder01Icon,
4 Notification01Icon,
5 Shield01Icon,
6} from '@hugeicons/core-free-icons';
7import { HugeiconsIcon } from '@hugeicons/react';
8import { IconTile } from '@/components/ui/icon-tile';
9
10export function Default() {
11 return (
12 <div className="flex items-center gap-3">
13 <IconTile>
14 <HugeiconsIcon icon={Folder01Icon} />
15 </IconTile>
16 <IconTile variant="elevated">
17 <HugeiconsIcon icon={Notification01Icon} />
18 </IconTile>
19 <IconTile variant="frame">
20 <HugeiconsIcon icon={CreditCardIcon} />
21 </IconTile>
22 <IconTile variant="solid" tone="primary">
23 <HugeiconsIcon icon={Shield01Icon} />
24 </IconTile>
25 </div>
26 );
27}

Installation

pnpm dlx nachui add icon-tile

Anatomy

1import { IconTile } from '@/components/ui/icon-tile';
1<IconTile variant="soft" tone="primary">
2 <SparklesIcon />
3</IconTile>
The tile fixes the box and the glyph size so icons line up across list rows, feature cards and empty states no matter which icon set you use. It takes an icon, initials or a short label as children. Color comes from a tone, which sets a --tile-color and --tile-contrast pair that every variant reads, so a custom color is one class away: className="[--tile-color:var(--color-pink-500)]".

Variants

Surfaces

outline is a bordered surface, elevated a muted fill with a background ring, soft a tinted surface with a faint halo, solid a filled tile with a contrasting glyph and frame a card inset inside a muted ring.
outline
elevated
soft
solid
frame
1import { SparklesIcon } from '@hugeicons/core-free-icons';
2import { HugeiconsIcon } from '@hugeicons/react';
3import { IconTile } from '@/components/ui/icon-tile';
4
5const VARIANTS = ['outline', 'elevated', 'soft', 'solid', 'frame'] as const;
6
7export function Variants() {
8 return (
9 <div className="flex flex-wrap items-end gap-6">
10 {VARIANTS.map((variant) => (
11 <div key={variant} className="flex flex-col items-center gap-2">
12 <IconTile variant={variant} tone="primary">
13 <HugeiconsIcon icon={SparklesIcon} />
14 </IconTile>
15 <span className="text-muted-foreground font-mono text-xs">{variant}</span>
16 </div>
17 ))}
18 </div>
19 );
20}

Sizes

Five sizes, each with a matching glyph size: 24, 32, 40, 48 and 56px.
xs
sm
default
lg
xl
1import { Rocket01Icon } from '@hugeicons/core-free-icons';
2import { HugeiconsIcon } from '@hugeicons/react';
3import { IconTile } from '@/components/ui/icon-tile';
4
5const SIZES = ['xs', 'sm', 'default', 'lg', 'xl'] as const;
6
7export function Sizes() {
8 return (
9 <div className="flex flex-wrap items-end gap-4">
10 {SIZES.map((size) => (
11 <div key={size} className="flex flex-col items-center gap-2">
12 <IconTile size={size} variant="elevated">
13 <HugeiconsIcon icon={Rocket01Icon} />
14 </IconTile>
15 <span className="text-muted-foreground font-mono text-xs">{size}</span>
16 </div>
17 ))}
18 </div>
19 );
20}

Tones

Semantic tones map to the theme tokens. The same tone works across every surface.
1import {
2 Alert02Icon,
3 CheckmarkCircle02Icon,
4 Delete02Icon,
5 InformationCircleIcon,
6 PaintBoardIcon,
7 UserIcon,
8 ZapIcon,
9} from '@hugeicons/core-free-icons';
10import { HugeiconsIcon } from '@hugeicons/react';
11import { IconTile } from '@/components/ui/icon-tile';
12
13const TONES = [
14 { tone: 'default', icon: PaintBoardIcon },
15 { tone: 'muted', icon: UserIcon },
16 { tone: 'primary', icon: ZapIcon },
17 { tone: 'success', icon: CheckmarkCircle02Icon },
18 { tone: 'warning', icon: Alert02Icon },
19 { tone: 'info', icon: InformationCircleIcon },
20 { tone: 'destructive', icon: Delete02Icon },
21] as const;
22
23export function Tones() {
24 return (
25 <div className="flex flex-col gap-4">
26 <div className="flex flex-wrap items-center gap-3">
27 {TONES.map(({ tone, icon }) => (
28 <IconTile key={tone} tone={tone} variant="soft">
29 <HugeiconsIcon icon={icon} />
30 </IconTile>
31 ))}
32 </div>
33 <div className="flex flex-wrap items-center gap-3">
34 {TONES.map(({ tone, icon }) => (
35 <IconTile key={tone} tone={tone} variant="solid">
36 <HugeiconsIcon icon={icon} />
37 </IconTile>
38 ))}
39 </div>
40 </div>
41 );
42}

Circular

radius="full" turns the tile into a circle, handy next to avatars.
1import { Camera01Icon, Globe02Icon, Mail01Icon } from '@hugeicons/core-free-icons';
2import { HugeiconsIcon } from '@hugeicons/react';
3import { IconTile } from '@/components/ui/icon-tile';
4
5export function Radius() {
6 return (
7 <div className="flex items-center gap-3">
8 <IconTile radius="full">
9 <HugeiconsIcon icon={Camera01Icon} />
10 </IconTile>
11 <IconTile radius="full" variant="soft" tone="info">
12 <HugeiconsIcon icon={Globe02Icon} />
13 </IconTile>
14 <IconTile radius="full" variant="solid" tone="success">
15 <HugeiconsIcon icon={Mail01Icon} />
16 </IconTile>
17 </div>
18 );
19}

Text

Initials or a short count fit in the same box as an icon.
IFNVMZ+3
1import { IconTile } from '@/components/ui/icon-tile';
2
3export function Text() {
4 return (
5 <div className="flex items-center gap-3">
6 <IconTile variant="soft" tone="primary">
7 IF
8 </IconTile>
9 <IconTile variant="solid">NV</IconTile>
10 <IconTile variant="frame" radius="full">
11 MZ
12 </IconTile>
13 <IconTile variant="elevated" size="lg">
14 +3
15 </IconTile>
16 </div>
17 );
18}

API Reference

IconTile

PropTypeDefaultDescription
variant'outline' | 'elevated' | 'soft' | 'solid' | 'frame''outline'Surface treatment
size'xs' | 'sm' | 'default' | 'lg' | 'xl''default'Tile and glyph size
radius'default' | 'full''default'Rounded corners or a full circle
tone'default' | 'muted' | 'primary' | 'success' | 'warning' | 'info' | 'destructive''default'Color pair used by the surface and the glyph
classNamestring-Additional CSS classes or CSS variable overrides
Renders a span and accepts every standard span attribute.
Found something to improve?

Notice a bug, typo, or missing detail on this page? Help us make the documentation better by opening a GitHub issue.

Create an Issue
Ctrl+I