Skip to content

Icon Button

A square button showing only an icon, with a required accessible label.

  • When there is room for text: use Button with an icon and a label.

Install

Terminal
pnpm dlx shadcn@latest add @acme/icon-button

Or import from the package: import { IconButton } from '@acme/react'

Examples

Button basic

icon-button-basic.tsx
import { Bold, Italic, Settings, Trash2 } from 'lucide-react'
import { IconButton } from '@/components/ui/icon-button'

export default function IconButtonBasic() {
  return (
    <div className="flex items-center gap-2">
      <IconButton label="Bold" size="sm">
        <Bold />
      </IconButton>
      <IconButton label="Italic" size="sm">
        <Italic />
      </IconButton>
      <IconButton label="Settings" variant="outline">
        <Settings />
      </IconButton>
      <IconButton label="Delete row" variant="destructive">
        <Trash2 />
      </IconButton>
    </div>
  )
}

Basic

tooltip-basic.tsx
import { Copy, Download, Share2 } from 'lucide-react'
import { IconButton } from '@/components/ui/icon-button'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'

const actions = [
  { label: 'Copy link', icon: Copy },
  { label: 'Download PDF', icon: Download },
  { label: 'Share', icon: Share2 },
]

export default function TooltipBasic() {
  return (
    <TooltipProvider>
      <div className="flex gap-1">
        {actions.map(({ label, icon: Icon }) => (
          <Tooltip key={label}>
            <TooltipTrigger
              render={
                <IconButton label={label} size="sm">
                  <Icon />
                </IconButton>
              }
            />
            <TooltipContent>{label}</TooltipContent>
          </Tooltip>
        ))}
      </div>
    </TooltipProvider>
  )
}

Native

The same component for iOS (SwiftUI, AcmeUI) and Android (Jetpack Compose, com.acme.ui), built on each platform's own controls with the same tokens.

AcmeIconButton

Swift
AcmeIconButton("Close", systemImage: "xmark") { dismiss() }
  • The label is required: it is the VoiceOver name and the pointer tooltip.
  • Icons are SF Symbols on iOS.
Icon Button on iOS, light mode
iOS, light mode
Icon Button on iOS, dark mode
iOS, dark mode

Props

Icon Button props
PropTypeDefaultDescription
label (required)string—Accessible name, required by the type. Pair with a Tooltip to show it to sighted users.
variant'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive''ghost'Visual emphasis.
size'sm' | 'md' | 'lg''md'32, 40 or 48px square.

Accessibility

Keyboard
KeyAction
EnterActivates
SpaceActivates
Role
button
You provide
  • label (enforced by TypeScript).
Built in
  • The icon is aria-hidden; label becomes aria-label.
WCAG 2.2 criteria
1.1.1, 2.5.8, 4.1.2

Don’t

  • Use an icon whose meaning is ambiguous without a tooltip.

Tokens

  • color.accent
  • color.ring
  • radius.md