Skip to content
design
Components

Icon button

A button whose only content is an icon: a square touch target, named by its label, with that name in a tooltip.

On this page
Icon buttons with the toolkit's own rule: one name per control, and the name is the tooltip.
Code
import { IconButton } from "@bosunkit/components/icon-button";
import { Check, X } from "lucide-react";
import type { ReactElement } from "react";

export const description: string =
  "Two icon buttons: each is a square touch target, named by its label, with the same words in a tooltip.";

export default function Acknowledge(): ReactElement {
  return (
    <div style={{ display: "flex", gap: "var(--space-sm)" }}>
      <IconButton label="Acknowledge" icon={<Check size={20} />} />
      <IconButton label="Dismiss" icon={<X size={20} />} variant="ghost" />
    </div>
  );
}

An icon button is a button at the icon size — a square of the kit's touch target size — whose only content is an icon. label is required and becomes the control's accessible name, and the same words are shown in a tooltip so a crew member who can see the control reads what it does.

One name per control. The icon is marked decorative, so it is not announced twice: the label names the action and the icon shows it. A control with no name is one the crew cannot identify, which is why the label is not an optional prop beside aria-label — it is the prop, and aria-label is wired here rather than passed in.

The tooltip is not the name. It opens on focus as well as on hover, so the label reaches a keyboard too, but nothing needed to act safely lives only in it: the name is on the button.

A shortcut

A control that has a keyboard shortcut shows it in the tooltip, in the kit's key chip.
Code
import { IconButton } from "@bosunkit/components/icon-button";
import { Command } from "lucide-react";
import type { ReactElement } from "react";

export const description: string =
  "A control that has a keyboard shortcut shows it in the tooltip, in the kit's key chip.";

export default function Shortcut(): ReactElement {
  return <IconButton label="Command palette" icon={<Command size={20} />} shortcut="Ctrl K" />;
}

When the control has a keyboard shortcut, the tooltip shows it in a kbd chip after the label.

Choose an action the icon can support

Use an icon-only control for a familiar action in a constrained region. When the action is unfamiliar or has significant consequences, show a text button. The accessible label describes the action, not the icon's shape. A tooltip supplements that name and does not provide a separate activation target.

For a toggle, keep its name stable and expose its pressed state through the underlying button attributes. The caller implements any displayed shortcut and its scope; showing a key chip does not install a handler. Verify disabled and pending behavior and the full target size even when the visible glyph is small.

Props

PropTypeDefaultDescription
variantButtonVariant | undefined–The button's emphasis: primary for the main action, danger for a destructive one, ghost for a quiet one.
textCaseButtonTextCase | undefined–How the label is cased: in capitals by default. none keeps the letters as written, for a label whose case carries meaning, such as a chess move in SAN (Nf3, exd5), a call sign or a chart number.
motionMotionProp | undefined–How the button moves. By default it fades its new label in when the label changes ("Acknowledge" to "Acknowledged"), keeping its focus, and has no entrance. true also scales it in as it mounts, wherever it is, and out when it leaves a MotionPresence; a preset (fade, rise, scale) or { enter, exit, change } chooses; false turns it off. It is named and pressable from the first frame.
refRef<HTMLButtonElement> | undefined–The button element.
labelrequiredstring–What the control does, in the crew's language — "Acknowledge", "Stop the timer". It is both the control's accessible name and the tooltip's text, so a crew member who cannot see the icon still knows what the button does. A whole translated phrase, never "Edit" joined to a noun.
iconrequiredReactNode–The icon, drawn at the control's size. It is marked decorative here: the label is the name, and an icon that carries its own name would be announced twice.
shortcutstring | undefined–A keyboard shortcut shown after the label in a key chip, such as Ctrl K, when the control has one.
testIdstring | undefined–Becomes data-testid on the tooltip's trigger, which is the button.

Also takes every attribute of Omit<ButtonProps, "size" | "children" | "aria-label" | "aria-labelledby">.