Build · New

Icon Button

A button with an icon instead of a label, for toolbars and repeated actions. It shares Button's styles, sizes and states, and always carries a written name for screen readers.

Preview

Mirrored is the same English content laid out right to left: it separates a mirroring bug from a translation one.

Installation

SoonInstalling from the registry opens at launch. Until then the command below is what it will be.
npx shadcn@latest add @ritla/icon-button

Dependencies it brings: @base-ui/react, @phosphor-icons/react

Usage

import { MagnifyingGlassIcon } from "@phosphor-icons/react/ssr";
import { IconButton } from "@/components/ui/icon-button";
<IconButton variant="outline" icon={MagnifyingGlassIcon} label="Search" />

Examples

Sizes

Each size is a square as tall as the Button of the same size (56, 48, 40 and 32px), so the two line up in a row. The tap target stays at least 48px at sm and xs.

Styles

Button's five styles with the same colors; the icon takes the label color. isDanger turns any style red, and inverted-ghost goes on colored surfaces.

Shape

square (default) takes the Button radius for its size; round is fully round, for floating actions and next to avatars.

States

loading puts the spinner in place of the icon and keeps focus and the name; disabled switches it off. Press Save, and change the label while loading (“Saving”).

Toolbar in Arabic

Back uses ArrowLeftIcon in both languages and points right in Arabic, because back runs against the reading direction. Search, notifications and the menu never mirror; the row follows the page direction.

Close button

The close button sits at the inline end, the left in Arabic. xs suits dense headers and stays easy to hit.

When to use a labeled Button

Icon buttons are for familiar icons (edit, share, search). A destructive action needs words, so use a labeled Button rather than a lone trash icon, and don't put two filled icon buttons side by side.

API reference

IconButton

Any other Base UI Button prop passes through (onClick, type…).

PropTypeDefaultDescription
iconIconComponentFigma's Change icon: a Phosphor or Kanz icon. Directional icons mirror in Arabic on their own.
labelstringRequired. The name screen readers announce (aria-label), in the page language.
shape"square" | "round""square"Figma's Shape: the Button radius, or a full circle.
variant"filled" | "tonal" | "outline" | "ghost" | "inverted-ghost""filled"Figma's Style, as on Button.
size"lg" | "md" | "sm" | "xs""lg"Figma's Size: a 56, 48, 40 or 32px square.
isDangerbooleanfalseFigma's isDanger: red, with a red focus ring.
loadingbooleanfalseState = Loading: the spinner replaces the icon, aria-busy, and the button stays focusable.
disabledbooleanfalseState = Disabled.
renderReactElementAnother element with the Icon Button look, usually a link. It keeps its semantics and takes label as its name.
classNamestringExtra classes merged with cn().

Accessibility

Keyboard

Keys are written for left-to-right. In right-to-left the arrow keys swap: the one pointing toward the reading direction moves forward.

KeyAction
TabMoves focus to the button and shows the focus ring (red with isDanger).
EnterSpaceActivates it. While loading, focus stays and the action doesn't repeat.

ARIA

  • label is required by the type, so an icon button can't ship without a name. It becomes aria-label; the icon is aria-hidden.
  • Write the name in the page language (“بحث”, not “Search”, in Arabic), and name the action, not the icon (“Close”, not “X”).
  • Loading sets aria-busy="true" and aria-disabled="true" instead of disabled, so focus isn't lost.
  • The tap target is at least 48px at every size (WCAG 2.5.8), even when the button is drawn at 32px.
  • In toolbars, sighted users need a tooltip too. It comes with the Tooltip component.

Arabic and RTL notes

Mirrors

  • Arrows and carets flip through <Icon>: Back with ArrowLeftIcon points right in Arabic.
  • Toolbar order mirrors with the page, and the close button stays at the inline end.

Does not mirror

  • The button itself never mirrors and has no RTL prop; only the icon decides.
  • Search, notifications, the menu, heart, download and the loading spinner stay the same in both languages.
Numerals
An icon button has no numerals. If you add a count badge over it, format it with formatNumber so it follows the numerals setting.
Arabic typography
No visible text; the name lives in label. Write it in natural Arabic: a screen reader speaks it with an Arabic voice when the page is lang="ar".
Mixed-direction text
A Latin brand inside an Arabic label (“مشاركة عبر WhatsApp”) reads correctly without <bdi>: aria-label is spoken, not displayed.

All components ›