A button that runs one action and shows it as an icon alone, such as zoom in or show help, named for screen readers by its required label.
When to use
Use IconButton for an action shown as an icon alone, one people know at a glance, such as zoom in, close or search.
| Use instead | When |
|---|---|
| Button | The action is named in words, or its icon would have to be guessed |
| LinkButton | Pressing it takes the reader to another page or place |
| Toolbar | Several actions sit together in one bar, one tab stop moved through with the arrows |
| MapControls | The buttons are the map's own: zoom, centre, the 3D toggle, the compass and the pause |
| FilterChip | The control turns a filter on and off |
On this page
Kongens Nytorv
Metro M1, M2 and M3.
Variants and states
| Rest | Hover | Pressed | Focus | Disabled | |
|---|---|---|---|---|---|
| Neutral | |||||
| Brand |
- Rest
- Hover
- Pressed
- Focus
- Disabled
Sizes
Mediumsize.control · 34 px
Large
Props
| Name | Type | Default | Description |
|---|---|---|---|
label* | string | — | The words that name the action, in sentence case, such as "Zoom in". Required: the icon is hidden from screen readers, so these words are the button's name. Never seen, read by screen readers. |
color | 'neutral' | 'brand' | 'neutral' | The intent: neutral is quiet ink, for every action but the main one; brand is the brand yellow, for the one main action of a screen. |
size | 'medium' | 'large' | 'medium' | The icon's step in the size.control square: medium is icon.size.400, for icons drawn on the 16 px grid; large is icon.size.450, for the top bar's icons drawn on the 18 px grid. |
disabled | boolean | false | Whether the button ignores the pointer and the keys. A disabled button leaves the tab order unless focusableWhenDisabled is set. |
children | ReactNode | — | The icon, such as an SVG from packages/perron/icons/ with the perron-icon class. Hidden from screen readers: label names the button. |
className | string | — | Reaches the root. className is merged after pn-IconButton. |
style | CSSProperties | — | Reaches the root. className is merged after pn-IconButton. |
ref | Ref<HTMLButtonElement> | — | Reaches the root. className is merged after pn-IconButton. |
label (required)string, default —- The words that name the action, in sentence case, such as "Zoom in". Required: the icon is hidden from screen readers, so these words are the button's name. Never seen, read by screen readers.
color'neutral' | 'brand', default'neutral'- The intent:
neutralis quiet ink, for every action but the main one;brandis the brand yellow, for the one main action of a screen. size'medium' | 'large', default'medium'- The icon's step in the
size.controlsquare:mediumisicon.size.400, for icons drawn on the 16 px grid;largeisicon.size.450, for the top bar's icons drawn on the 18 px grid. disabledboolean, defaultfalse- Whether the button ignores the pointer and the keys. A disabled button leaves the tab order unless
focusableWhenDisabledis set. childrenReactNode, default —- The icon, such as an SVG from
packages/perron/icons/with theperron-iconclass. Hidden from screen readers:labelnames the button. classNamestring, default —- Reaches the root.
classNameis merged afterpn-IconButton. styleCSSProperties, default —- Reaches the root.
classNameis merged afterpn-IconButton. refRef<HTMLButtonElement>, default —- Reaches the root.
classNameis merged afterpn-IconButton.
Use it
import { IconButton } from '@mylder/perron'Ask your agent
get_reference({ library: "base-ui", component: "Button" })Keyboard and ARIA
From the Base UI reference for Button and the installed useButton, as on Button. "From" says who does it.
| Key | Does | From |
|---|---|---|
Tab, Shift+Tab | Moves focus to the button and away; a disabled button is skipped unless focusableWhenDisabled | The browser, and Base UI |
Enter | Activates the button: fires onClick, or submits the form with type="submit" | The browser; Base UI for a non-button render |
Space | Activates the button on release | The browser; Base UI for a non-button render |
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
root | button, native; role="button" from Base UI when render gives a non-button element | Its text content: the label in the VisuallyHidden span; aria-label or aria-labelledby from the caller win | Disabled: the native disabled, or aria-disabled with focusableWhenDisabled |
icon | none: aria-hidden="true" | none | none |
label | none: text inside the button | none: it is the name | none |
What axe won't catch, from the contract, each with how this component meets it:
- Everything the eye is told, the ear is told, for every shape each prop accepts: the icon is
aria-hiddenandlabelsays in words what it shows, as Icons asks of an icon alone;colorcarries emphasis, not meaning; disabled is announced by the native attribute oraria-disabled. - Every landmark and named region has an accessible name: none here; a button is neither.
- Every default label can be overridden: none here; IconButton owns no strings, and
labelis the caller's. - Every shape the type accepts renders, in every variant:
childrenrenders a string, an element and a list alike, centred in the square, in both colours and both sizes, and the icon span clips a string wider than the square so it stays inside;labelis astring. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; IconButton keeps no hidden copy and collapses nothing. TheVisuallyHiddenlabel is the name, not a copy. - Native semantics first: a native
<button>from Base UI'sButton, named by its own text; withrenderandnativeButton={false}, Base UI'srole="button". No ARIA of its own. - Focus moves in reading order and returns on close: the button is one tab stop in document order, and opens nothing of its own to return from.
- Every target is at least
size.target-minsquare: every IconButton issize.control(34 px) square, in both sizes. - Loops stop when the system asks for less motion: none here; IconButton has no loop and no transition.
Owned strings
No owned strings: every word comes from the caller, as label.
Do and don't
For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | must | Give label the action in sentence case, as a verb and what it acts on: "Zoom in", "Centre the map" | Name the icon rather than the action ("Plus", "Magnifier"), or write Title Case or an exclamation mark (Content design) | review |
| DD-2 | should | Use IconButton only where the icon is one people know at a glance, such as zoom, locate, close or search, and use Button with words otherwise | Put an icon whose meaning has to be guessed in an IconButton: the label reaches only screen readers, and the eye gets the icon alone | review |
| DD-3 | should | Give size="large" to an icon drawn on the 18 px grid (monitor, info), and keep the default medium for the 16 px ones | Set --perron-icon-size or a width on the icon yourself, or give a 16 px icon large: an icon drawn on one grid blurs when scaled to another | review |
| DD-4 | must | Give one action per screen color="brand", for its main action | Use brand for emphasis, or set two brand actions on one screen | review |
| DD-5 | should | Set icon buttons on a panel, a sheet or the top bar's glass, which mark where they sit | Float a neutral icon button straight over the map: its transparent fill disappears on the land and water | review |
| DD-6 | must | Put each action of a Toolbar in a ToolbarButton, so the arrow keys reach it | Put an IconButton inside a Toolbar: it falls out of the arrow-key order and adds a tab stop | review |
| DD-7 | must | Use a toggle component, such as FilterChip, for an icon that turns something on and off | Set aria-pressed on an IconButton and restyle it: IconButton keeps no pressed state, and a toggle says its state in words | review |
| DD-8 | must | Set disabled when the action can't run, with focusableWhenDisabled so the button can still be reached and its name heard | Restyle a disabled icon button with opacity: disabled is color.text.tertiary, a colour | review |