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
npx shadcn@latest add @ritla/icon-buttonDependencies 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…).
| Prop | Type | Default | Description |
|---|---|---|---|
icon | IconComponent | Figma's Change icon: a Phosphor or Kanz icon. Directional icons mirror in Arabic on their own. | |
label | string | Required. 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. |
isDanger | boolean | false | Figma's isDanger: red, with a red focus ring. |
loading | boolean | false | State = Loading: the spinner replaces the icon, aria-busy, and the button stays focusable. |
disabled | boolean | false | State = Disabled. |
render | ReactElement | Another element with the Icon Button look, usually a link. It keeps its semantics and takes label as its name. | |
className | string | Extra 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.
| Key | Action |
|---|---|
| Tab | Moves focus to the button and shows the focus ring (red with isDanger). |
| EnterSpace | Activates it. While loading, focus stays and the action doesn't repeat. |
ARIA
labelis required by the type, so an icon button can't ship without a name. It becomesaria-label; the icon isaria-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"andaria-disabled="true"instead ofdisabled, 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 withArrowLeftIconpoints 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
formatNumberso 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 islang="ar". - Mixed-direction text
- A Latin brand inside an Arabic
label(“مشاركة عبر WhatsApp”) reads correctly without<bdi>:aria-labelis spoken, not displayed.