Components

Icon Button

Circular button with glassmorphic styling for icon-based actions

Icon Button

A circular button component designed for icon-based actions. Features glassmorphic styling with backdrop blur, inset shadows, and gradient-masked borders. Includes specialized variants for common actions like plus, close, and arrow buttons.

Usage

import { IconButton, PlusButton, CloseButton, ArrowButton } from "@/components/ui/icon-button";

export default function Example() {
  return (
    <div className="flex gap-4">
      <IconButton>
        <SettingsIcon className="w-4 h-4" />
      </IconButton>
      <PlusButton />
      <CloseButton />
      <ArrowButton direction="right" />
    </div>
  );
}

Components

IconButton

The base icon button component with glassmorphic styling.

PlusButton

Pre-configured button with a plus icon for "add" actions.

CloseButton

Pre-configured button with an X icon for "close" or "dismiss" actions.

ArrowButton

Pre-configured button with an arrow icon supporting four directions.

Props

IconButton Props

PropTypeDefaultDescription
variant"default" | "ghost" | "outline" | "solid""default"Visual style variant
size"sm" | "default" | "lg""default"Button size
asChildbooleanfalseRender as child element (Radix Slot)

ArrowButton Props

PropTypeDefaultDescription
direction"up" | "down" | "left" | "right""right"Arrow direction
...IconButtonProps--All IconButton props

Variants

Style Variants

// Default - glassmorphic with blur and gradient border
<IconButton variant="default">
  <Icon />
</IconButton>

// Ghost - transparent, hover reveals background
<IconButton variant="ghost">
  <Icon />
</IconButton>

// Outline - transparent with border
<IconButton variant="outline">
  <Icon />
</IconButton>

// Solid - 10% opacity background
<IconButton variant="solid">
  <Icon />
</IconButton>

Size Variants

// Small - 40px
<IconButton size="sm">
  <Icon className="w-3 h-3" />
</IconButton>

// Default - 60px
<IconButton size="default">
  <Icon className="w-4 h-4" />
</IconButton>

// Large - 80px
<IconButton size="lg">
  <Icon className="w-5 h-5" />
</IconButton>

Examples

Add Button

<PlusButton onClick={() => handleAdd()} />

Close Modal

<CloseButton 
  onClick={() => setOpen(false)}
  aria-label="Close modal"
/>
<div className="flex gap-2">
  <ArrowButton direction="left" onClick={handlePrev} />
  <ArrowButton direction="right" onClick={handleNext} />
</div>

Custom Icon

<IconButton variant="default" size="default">
  <HeartIcon className="w-4 h-4 text-[var(--ui-text-primary)]" />
</IconButton>
import Link from "next/link";

<IconButton asChild>
  <Link href="/settings">
    <SettingsIcon className="w-4 h-4" />
  </Link>
</IconButton>

Action Group

<div className="flex gap-2">
  <IconButton variant="ghost" size="sm">
    <EditIcon className="w-3 h-3" />
  </IconButton>
  <IconButton variant="ghost" size="sm">
    <CopyIcon className="w-3 h-3" />
  </IconButton>
  <IconButton variant="ghost" size="sm">
    <TrashIcon className="w-3 h-3" />
  </IconButton>
</div>

Design Tokens

Dimensions

SizeDimensionsBorder Radius
sm40px × 40pxvar(--radius-sm) (12px)
default60px × 60pxvar(--radius-lg) (16px)
lg80px × 80pxvar(--radius-xl) (32px)

Effects (Default Variant)

TokenValueDescription
Outer bordervar(--ui-stroke-selected)40% opacity border
Shadowvar(--shadow-1)Composite inset + drop
Backgroundvar(--gradient-overlay-170)Glassmorphic gradient
Blurvar(--blur-sm) (6px)Backdrop blur
Inner bordervar(--ui-stroke-subtle)10% opacity, masked

Icon Sizing

Button SizeRecommended Icon Size
sm12px - 14px
default16px - 20px
lg20px - 24px

Glassmorphic Structure

The default variant uses a layered structure:

  1. Outer container - Border and shadow
  2. ::before pseudo - Glassmorphic background with blur
  3. ::after pseudo - Gradient-masked inner border
  4. Content - Icon with z-index above layers
┌─────────────────────┐  ← Outer border (1.5px)
│  ┌───────────────┐  │  ← 3px inset
│  │  ::before     │  │  ← Blur + gradient bg
│  │  ┌─────────┐  │  │
│  │  │  Icon   │  │  │  ← Content (z-10)
│  │  └─────────┘  │  │
│  │  ::after      │  │  ← Masked border
│  └───────────────┘  │
└─────────────────────┘

Found In

  • Bento10 - Plus button in avatar group
  • Bento11 - Action buttons
  • Bento20 - Arrow navigation
  • Bento28 - Control buttons

Accessibility

  • Full keyboard navigation support
  • Focus ring with focus-visible styling
  • Disabled state with reduced opacity
  • aria-label support for icon-only buttons
  • asChild prop for semantic link rendering
  • Built-in icons include aria-hidden="true"

Best Practices

// Always provide accessible labels for icon-only buttons
<IconButton aria-label="Settings">
  <SettingsIcon />
</IconButton>

// Or use sr-only text
<IconButton>
  <SettingsIcon aria-hidden="true" />
  <span className="sr-only">Settings</span>
</IconButton>

On this page