Variants
Accent
The single highest-emphasis icon action on a page. Restricted to lg and xl sizes; defaults to xl.
<IconButton icon={MaterialSearch} aria-label="Search" variant="accent" />Primary
Important icon actions that aren't the page-level CTA.
<IconButton icon={MaterialSearch} aria-label="Search" variant="primary" />Secondary
Paired with a primary to offer an alternative. Has a visible border.
<IconButton icon={MaterialFavorite} aria-label="Add to favourites" variant="secondary" />Tertiary
Low-emphasis icon actions — toolbar toggles, supplementary controls. Transparent background.
<IconButton icon={MaterialSettings} aria-label="Settings" variant="tertiary" />Inverse
Inside an inverse <Surface> this happens automatically — Surface is the source of truth. Pass inverse explicitly only for a dark or branded background that isn’t a Surface. Toggle to dark theme to see the canvas context.
Accent inverse
<Surface tone="inverse" className="rounded-lg p-6">
<IconButton icon={MaterialSearch} aria-label="Search" variant="accent" inverse />
</Surface>Inside an inverse Surface
Surface is the source of truth: inside an inverse Surface the icon button adopts inverse styling automatically — no inverse prop needed. Pass inverse explicitly only on a dark background that isn't a Surface.
<Surface tone="inverse" className="rounded-lg p-6 flex gap-4">
<IconButton icon={MaterialHome} aria-label="Home" variant="primary" />
<IconButton icon={MaterialFavorite} aria-label="Favourites" variant="secondary" />
<IconButton icon={MaterialSettings} aria-label="Settings" variant="tertiary" />
</Surface>Sizes
The shell is always square. accent only accepts lg and xl, so the size ramp below uses primary.
Small
40 × 40 px. Dense layouts, data tables, inline actions.
<IconButton icon={MaterialSearch} aria-label="Search" variant="primary" size="sm" />Medium
48 × 48 px. The default size for most layouts.
<IconButton icon={MaterialSearch} aria-label="Search" variant="primary" size="md" />Large
56 × 56 px. Larger touch targets and prominent actions.
<IconButton icon={MaterialSearch} aria-label="Search" variant="primary" size="lg" />Extra large
64 × 64 px. Page-level CTAs. The default size for the accent variant.
<IconButton icon={MaterialSearch} aria-label="Search" variant="primary" size="xl" />States
Disabled
Applied when the action is permanently unavailable in the current state.
<IconButton icon={MaterialSearch} aria-label="Search" variant="primary" disabled />Loading
Replaces the glyph with a spinner while an async operation is in progress. The accessible label is retained.
<IconButton icon={MaterialSearch} aria-label="Searching…" variant="primary" loading />When to use
Use an icon button for a compact action where a recognisable glyph communicates the intent on its own — search, favourite, settings, close. Because there is no visible text, the glyph must be unambiguous and you must always provide an accessible label for assistive technology.
Prefer a text Button when the action’s meaning isn’t obvious from an icon alone, or when you have room for a label. Icon buttons trade clarity for compactness, so reserve them for well-understood, conventional actions.
Variants
- Accent: the single most important icon action on a page. One accent button per viewport. Restricted to
lgandxlsizes. - Primary: important icon actions that aren’t the page-level CTA. One primary per distinct area.
- Secondary: supporting actions paired alongside a primary. Has a visible border.
- Tertiary: low-emphasis icon actions — toolbar toggles, supplementary controls. Transparent background.
Do
Give every icon button a meaningful aria-label describing the action.
Don't
Don't rely on an ambiguous or unfamiliar glyph alone to convey the action — pick an icon users will recognise.
Sizes
The shell is square at every size. accent is locked to lg and xl.
| Size | Dimensions | Glyph | Typical use |
|---|---|---|---|
xl | 64 × 64 px | 32 px | Page-level CTAs; default and largest for accent |
lg | 56 × 56 px | 28 px | Larger touch targets, prominent actions; smallest for accent |
md | 48 × 48 px | 24 px | Default for most layouts |
sm | 40 × 40 px | 22 px | Compact UI — data tables, inline actions |
Default size is xl for accent and md for all other variants.
When not to use
- Actions whose meaning isn’t obvious: use a text
Buttonwith a clear label instead. - Navigation: use a link (
<a>on web, or your app’s navigation primitive on native). Buttons are for actions, not destinations. - Multiple accent or primary icon buttons: if everything is high-emphasis, nothing is.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| icon * | ComponentType<SVGProps<SVGSVGElement>> (web) / ComponentType<SvgProps> (native) | - | Glyph component from @checkatrade/icons. Rendered hidden from assistive technology — the label carries the meaning. |
| aria-label * | string | - | Web — required. There is no visible text, so the accessible name must be provided explicitly. |
| accessibilityLabel * | string | - | Native — required. The accessible name announced by screen readers. |
| variant | 'accent' | 'primary' | 'secondary' | 'tertiary' | 'primary' | Visual style. accent is restricted to size lg or xl at the type level. |
| size | 'sm' | 'md' | 'lg' | 'xl' | 'xl' for accent, 'md' for all others | Controls the square shell and glyph size. accent only accepts lg or xl. |
| inverse | boolean | surrounding Surface tone | Swaps all colours to their inverse token equivalents. Defaults to the surrounding Surface tone — inverse inside `<Surface tone="inverse">`. Pass explicitly to force it on/off, e.g. on a dark background that is not a Surface. |
| disabled | boolean | false | Prevents interaction and applies disabled token colours. |
| loading | boolean | false | Shows a spinner in place of the glyph, disables interaction, and sets aria-busy="true" (busy on native). The accessible label is retained. |
| onClick | () => void | - | Web — called on click. No-op when disabled or loading. |
| onPress | () => void | - | Native — called on press. No-op when disabled or loading. |
| data-testid | string | - | Web — passed to the root button for test targeting. |
| testID | string | - | Native — passed to the root Pressable and the spinner for test targeting. |
Import
Web
import { IconButton } from '@checkatrade/components-web';
import { MaterialHome } from '@checkatrade/icons/react';Native
import { IconButton } from '@checkatrade/components-native';
import Home from '@checkatrade/icons/rn/home';Basic usage
<IconButton icon={MaterialHome} aria-label="Home" variant="accent" />
<IconButton icon={MaterialSearch} aria-label="Search" variant="primary" />
<IconButton icon={MaterialFavorite} aria-label="Add to favourites" variant="secondary" />
<IconButton icon={MaterialSettings} aria-label="Settings" variant="tertiary" />Inverse on a dark background
<div style={{ background: 'var(--color-background-surface-brand-primary-default)', padding: '2rem' }}>
<IconButton icon={MaterialHome} aria-label="Home" variant="accent" inverse />
</div>Loading state
<IconButton icon={MaterialSearch} aria-label="Searching…" variant="primary" loading /> Platform status
| Platform / Area | Status |
|---|---|
| Design (Figma) | Beta |
| Web (React) | Beta |
| Native (React Native) | Beta |
| iOS (Swift) | Planned |
| Android (Kotlin) | Planned |
| Accessibility audit | Planned |
Accessibility
Web
- Uses a native
<button>element — keyboard accessible by default. aria-labelis required: there is no visible text, so the accessible name must always be provided.- The glyph is rendered with
aria-hidden="true"so it isn’t announced a second time — the label alone carries the meaning. - Loading state sets
aria-busy="true", and thearia-labelis retained as the accessible name while the spinner is shown. - Focus ring is provided globally via
@checkatrade/tokens/css/base—button:focus-visiblegets a 3px solid outline with 2px offset. The inverse focus ring switches automatically viadata-inverseon the underlying element.
React Native
- Uses
PressablewithaccessibilityRole="button"— announced as a button by screen readers on iOS (VoiceOver) and Android (TalkBack). accessibilityLabelis required: it provides the accessible name announced by screen readers.- The glyph is wrapped with
accessibilityElementsHiddenandimportantForAccessibility="no-hide-descendants"so it isn’t announced separately from the label. - Loading state sets
accessibilityState={{ busy: true }}.
Both platforms
- Minimum dimensions are
40 × 40px(sm), meeting WCAG 2.5.5 (AAA) touch target guidance at every size. accentis locked tolg | xlto ensure the page-level CTA always has sufficient visual weight and touch target size.
No releases yet.