Icon button
StableA square button with just an icon. The label is required: it is the accessible name and the tooltip.
For toolbars and tight rows where a word would crowd the layout. The label names the action, not the picture (“Delete task”, not “Trash”), and doubles as the hover tooltip so sighted mouse users get the same words.
Updated View source
In a toolbar
import { IconButton } from '@rchursin/product/ui'
/** The label is required: it is the accessible name and the tooltip. Name the action, not the picture. */export default function IconButtonBasic() { return ( <div className="flex items-center justify-center gap-2"> <IconButton icon="pencil" label="Edit task" /> <IconButton icon="copy" label="Duplicate task" /> <IconButton icon="archive" label="Archive task" /> <IconButton icon="trash" label="Delete task" /> </div> )}Usage
import { IconButton } from '@rchursin/product/ui'<IconButton icon="x" label="Close panel" onClick={close} />Examples
Sizes and finishes
xs 24 · sm 28 · md 32 · lg 36 (shown on secondary, so each square is visible), then ghost, secondary and primary.
import { IconButton } from '@rchursin/product/ui'
/** Sizes on the secondary finish, so each square shows; then the three finishes at md. */export default function IconButtonVariants() { return ( <div className="flex flex-wrap items-center justify-center gap-6"> <div className="flex items-center gap-2"> <IconButton icon="plus" label="Add" size="xs" variant="secondary" /> <IconButton icon="plus" label="Add" size="sm" variant="secondary" /> <IconButton icon="plus" label="Add" size="md" variant="secondary" /> <IconButton icon="plus" label="Add" size="lg" variant="secondary" /> </div> <div className="flex items-center gap-2"> <IconButton icon="sliders" label="Filters" variant="ghost" /> <IconButton icon="sliders" label="Filters" variant="secondary" /> <IconButton icon="sliders" label="Filters" variant="primary" /> </div> </div> )}API
Icon button props
| Prop | Type | Default | Description |
|---|---|---|---|
iconrequired | IconName | – | The icon to draw. |
labelrequired | string | – | Accessible name and tooltip. Name the action: “Archive task”. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | Square of 24, 28, 32 or 36 pixels. |
variant | 'ghost' | 'secondary' | 'primary' | 'ghost' | The finish. |
noTooltip | boolean | false | Hide the native tooltip when a visible label sits right next to the button. |
Accessibility
Keyboard
| Key | What it does |
|---|---|
| EnterSpace | Presses the button. |
- aria-label carries the name, so screen readers say “Archive task, button”.
- The smallest size (24 pixels) still meets WCAG 2.2’s minimum target size.
Guidelines
Do
- Use icons people already know: close, edit, more, search.
- Group related icon buttons and keep their order the same everywhere.
Don’t
- Don’t use an icon button for the main action of a view.
- Don’t leave out the label, even when the icon seems obvious.
In use
Used on this site
Related
- ButtonThe lit-metal button in five finishes and five sizes, with icons, a loading state and shortcut hints.
- IconOne component for all 161 icons: a 24-pixel grid, a 1.5 stroke, square ends, coloured by the text around it.
- TooltipA few words on hover (after a short wait) or keyboard focus, in the top layer. Esc hides it. Best for naming icon buttons.
Source
The component’s own files, exactly as they run on this site.
/** * App buttons: the same lit-metal finish as the site buttons (styles/luxe.css), in denser sizes. * * <Button>Save</Button> graphite (silver in dark mode) * <Button variant="secondary" icon="plus">New task</Button> pearl * <Button variant="ghost" size="sm">Cancel</Button> * <IconButton icon="x" label="Close" /> icon only: the label is the accessible name + tooltip * * Sizes: xs 24 · sm 28 · md 32 (default) · lg 36 · xl 40 (auth screens). All clear the 24px target minimum. */import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from "react"import { cx } from "../../components/cx"import { Icon, type IconName } from "../icons/Icon"import { comboKeys, useIsApple } from "../lib/hotkeys"
export type ButtonVariant = "primary" | "secondary" | "ghost" | "outline" | "inverse"export type ButtonSize = "xs" | "sm" | "md" | "lg" | "xl"
const variants: Record<ButtonVariant, string> = { primary: "lux-btn-ink",