Button

An interactive control that triggers an action when pressed.

Import

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

Examples

Default

<Button>Button</Button>

Emphasis

<div className='flex flex-row flex-wrap gap-2'>
  <Button emphasis='strong'>Strong</Button>
  <Button emphasis='normal'>Normal</Button>
  <Button emphasis='subtle'>Subtle</Button>
  <Button emphasis='subtler'>Subtler</Button>
</div>

Sizes

<div className='flex flex-row flex-wrap items-center gap-2'>
  <Button size='xs'>Extra small</Button>
  <Button size='sm'>Small</Button>
  <Button size='md'>Medium</Button>
  <Button size='lg'>Large</Button>
</div>

Intents

Neutral is the default intent. Each intent communicates a different purpose: accent for primary actions, danger for destructive actions, and so on. Hover and focus states adapt automatically.

<div className='grid gap-2'>
  <div className='flex flex-row flex-wrap gap-2'>
    <Button emphasis='strong' intent='neutral'>Neutral</Button>
    <Button emphasis='strong' intent='accent'>Accent</Button>
    <Button emphasis='strong' intent='brand'>Brand</Button>
    <Button emphasis='strong' intent='info'>Info</Button>
    <Button emphasis='strong' intent='success'>Success</Button>
    <Button emphasis='strong' intent='warning'>Warning</Button>
    <Button emphasis='strong' intent='danger'>Danger</Button>
  </div>
  <div className='flex flex-row flex-wrap gap-2'>
    <Button emphasis='normal' intent='neutral'>Neutral</Button>
    <Button emphasis='normal' intent='accent'>Accent</Button>
    <Button emphasis='normal' intent='brand'>Brand</Button>
    <Button emphasis='normal' intent='info'>Info</Button>
    <Button emphasis='normal' intent='success'>Success</Button>
    <Button emphasis='normal' intent='warning'>Warning</Button>
    <Button emphasis='normal' intent='danger'>Danger</Button>
  </div>
  <div className='flex flex-row flex-wrap gap-2'>
    <Button emphasis='subtle' intent='neutral'>Neutral</Button>
    <Button emphasis='subtle' intent='accent'>Accent</Button>
    <Button emphasis='subtle' intent='brand'>Brand</Button>
    <Button emphasis='subtle' intent='info'>Info</Button>
    <Button emphasis='subtle' intent='success'>Success</Button>
    <Button emphasis='subtle' intent='warning'>Warning</Button>
    <Button emphasis='subtle' intent='danger'>Danger</Button>
  </div>
  <div className='flex flex-row flex-wrap gap-2'>
    <Button emphasis='subtler' intent='neutral'>Neutral</Button>
    <Button emphasis='subtler' intent='accent'>Accent</Button>
    <Button emphasis='subtler' intent='brand'>Brand</Button>
    <Button emphasis='subtler' intent='info'>Info</Button>
    <Button emphasis='subtler' intent='success'>Success</Button>
    <Button emphasis='subtler' intent='warning'>Warning</Button>
    <Button emphasis='subtler' intent='danger'>Danger</Button>
  </div>
</div>

States

Hover and focus states use the intent color scale automatically via is-interactive.

<div className='grid gap-4'>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Default</p>
    <div><Button>Button</Button></div>
  </div>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Disabled</p>
    <div><Button disabled>Button</Button></div>
  </div>
</div>

Href

Pass href to render the 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 hrefs (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-2'>
  {/* Internal — routes through RoadieLinkProvider */}
  <Button href='/checkout' emphasis='strong' intent='accent'>Checkout</Button>

  {/* External — auto target='_blank' rel='noopener noreferrer' */}
  <Button href='https://oztix.com.au' emphasis='normal'>
    Open Oztix
    <ArrowSquareOut weight='bold' className='size-4' />
  </Button>

  {/* Protocol — plain <a>, no target/rel */}
  <Button href='mailto:hello@oztix.com.au' emphasis='subtle'>
    <Envelope weight='bold' className='size-4' />
    Email us
  </Button>
</div>

Hover each button — the browser status bar shows the resolved href exactly as Roadie rendered it. See Linking for the full reference: provider setup, the external/internal/protocol decision tree, and the external/target/rel overrides.

Escape hatch

For typed access to anchor-only DOM props (download, hreflang, referrerPolicy) or full element control, use Base UI's render prop. Passing both href and render triggers a one-shot dev warning — render wins, provider routing is silently disabled.

<Button render={<a href='/spec.pdf' download='spec.pdf' />}>
  Download spec
</Button>

Accessibility

  • Keyboard: Enter or Space activates the button. Focus is indicated by a semi-transparent ring via is-interactive.
  • ARIA: Uses native <button> element. disabled sets aria-disabled automatically.
  • IconButton: Requires an aria-label prop (enforced by TypeScript) since there is no visible text.

API reference

Button

Base UI
focusableWhenDisabledboolean

Whether the button should be focusable when disabled.

Defaults to false.

intent"neutral" | "brand" | "brand-secondary" | "accent" | "danger" | "success" | "warning" | "info" | null
emphasis"strong" | "normal" | "subtle" | "subtler" | null
size"xs" | "sm" | "md" | "lg" | "icon-xs" | "icon-sm" | "icon-md" | "icon-lg" | 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.

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.

Inherited from HTMLAttributes

relstring

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

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.