IconButton

A square button for icon-only actions.

Import

import { IconButton } from '@oztix/roadie-components'

Examples

Default

Always provide an aria-label since there is no visible text.

<IconButton aria-label='Add item'>
  <Plus weight='bold' />
</IconButton>

Emphasis

<div className='flex flex-row flex-wrap gap-2'>
  <IconButton aria-label='Strong' emphasis='strong'>
    <Star weight='bold' />
  </IconButton>
  <IconButton aria-label='Normal' emphasis='normal'>
    <Star weight='bold' />
  </IconButton>
  <IconButton aria-label='Subtle' emphasis='subtle'>
    <Star weight='bold' />
  </IconButton>
  <IconButton aria-label='Subtler' emphasis='subtler'>
    <Star weight='bold' />
  </IconButton>
</div>

Sizes

The default size is md. All sizes maintain square proportions.

<div className='flex flex-row flex-wrap items-center gap-2'>
  <IconButton aria-label='Extra small' size='xs'>
    <Heart weight='bold' />
  </IconButton>
  <IconButton aria-label='Small' size='sm'>
    <Heart weight='bold' />
  </IconButton>
  <IconButton aria-label='Medium' size='md'>
    <Heart weight='bold' />
  </IconButton>
  <IconButton aria-label='Large' size='lg'>
    <Heart weight='bold' />
  </IconButton>
</div>

The legacy icon-xs / icon-sm / icon-md / icon-lg size literals are still accepted for backwards compatibility (marked @deprecated in TypeScript) but new code should use the plain xs / sm / md / lg names above.

Intents

<div className='grid gap-2'>
  <div className='flex flex-row flex-wrap gap-2'>
    <IconButton aria-label='Neutral' emphasis='strong' intent='neutral'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Accent' emphasis='strong' intent='accent'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Brand' emphasis='strong' intent='brand'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Info' emphasis='strong' intent='info'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Success' emphasis='strong' intent='success'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Warning' emphasis='strong' intent='warning'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Danger' emphasis='strong' intent='danger'><CheckCircle weight='bold' /></IconButton>
  </div>
  <div className='flex flex-row flex-wrap gap-2'>
    <IconButton aria-label='Neutral' emphasis='normal' intent='neutral'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Accent' emphasis='normal' intent='accent'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Brand' emphasis='normal' intent='brand'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Info' emphasis='normal' intent='info'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Success' emphasis='normal' intent='success'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Warning' emphasis='normal' intent='warning'><CheckCircle weight='bold' /></IconButton>
    <IconButton aria-label='Danger' emphasis='normal' intent='danger'><CheckCircle weight='bold' /></IconButton>
  </div>
</div>

States

<div className='grid gap-4'>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Default</p>
    <div><IconButton aria-label='Favorite'><Heart weight='bold' /></IconButton></div>
  </div>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Disabled</p>
    <div><IconButton aria-label='Favorite' disabled><Heart weight='bold' /></IconButton></div>
  </div>
</div>

Href

Pass href to render the icon button as a routed anchor. Roadie picks the right element + safety attributes based on the href shape: internal routes go through your configured RoadieLinkProvider; external (https://…) auto-render with target='_blank' rel='noopener noreferrer'; protocol hrefs (mailto: / tel: / sms:) render plain anchors.

<div className='flex flex-row flex-wrap items-center gap-3'>
  {/* Internal — routes through RoadieLinkProvider */}
  <IconButton aria-label='View cart' href='/cart' emphasis='strong' intent='accent'>
    <ShoppingCart weight='bold' />
  </IconButton>

  {/* External — auto target='_blank' rel='noopener noreferrer' */}
  <IconButton aria-label='Open Oztix in a new tab' href='https://oztix.com.au' emphasis='normal'>
    <ArrowSquareOut weight='bold' />
  </IconButton>

  {/* Protocol — plain <a>, no target/rel */}
  <IconButton aria-label='Email support' href='mailto:hello@oztix.com.au' emphasis='subtle'>
    <Envelope weight='bold' />
  </IconButton>

  {/* Protocol — plain <a> */}
  <IconButton aria-label='Call support' href='tel:+61400000000' emphasis='subtle'>
    <Phone weight='bold' />
  </IconButton>
</div>

Hover each button — the browser status bar shows the resolved href exactly as Roadie rendered it (note the mailto: / tel: URLs vs the routed paths). See Linking for the full reference, including external / target / rel overrides.

Escape hatch

For typed access to anchor-only DOM props (e.g. download on a file link) or full element control, use Base UI's render prop. Passing both href and render triggers a one-shot dev warning — render wins.

<IconButton aria-label='Download spec' render={<a href='/spec.pdf' download='spec.pdf' />}>
  <Download weight='bold' />
</IconButton>

Guidelines

  • Always provide an aria-label to describe the action since there is no visible text.
  • For icon links that navigate, prefer <IconButton href={…}> and wire RoadieLinkProvider at the app root. The legacy LinkIconButton component is @deprecated and will be removed in v3.0.0.

API reference

IconButton

intent"neutral" | "brand" | "brand-secondary" | "accent" | "danger" | "success" | "warning" | "info" | null
emphasis"strong" | "normal" | "subtle" | "subtler" | null
hrefstring

Pass a URL to render the button as a routed anchor instead of a `<button>`. Internal hrefs route through the configured `RoadieLinkProvider` (or fall back to plain `<a>`); external hrefs (`http(s)://`, `//…`) render as `<a target='_blank' rel='noopener noreferrer'>`; `mailto:` / `tel:` / `sms:` render as plain `<a>`. Pair with `external`, `target`, or `rel` to override the defaults.

externalboolean

Force external-link treatment regardless of `href` shape. Useful for first-party URLs that should still open in a new tab, or for an `https://` URL that should route internally through the provider.

targetstring

Override the auto `target='_blank'` default on external hrefs.

aria-labelstring
Required
size"xs" | "sm" | "md" | "lg" | "icon-xs" | "icon-sm" | "icon-md" | "icon-lg"

Icon-button sizing. Use `'xs' | 'sm' | 'md' | 'lg'` (plain) — the `'icon-*'` aliases are accepted for backwards compatibility but discouraged.

Defaults to md.

Inherited from HTMLAttributes

relstring

Override the auto `rel='noopener noreferrer'` default on external hrefs.

Inherited from ButtonProps

focusableWhenDisabledboolean

Whether the button should be focusable when disabled.

Defaults to false.

Inherited from NativeButtonProps

nativeButtonboolean

Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (e.g. `<div>`).

Defaults to true.