RoadieRoadie
  • Home
  • Foundations
  • Tokens
  • Components
  • Charts
  • Widgets
  • Appearance
HomeFoundationsComponents
Appearance

Components

  • Navigation

    • Breadcrumb
    • Navigator
    • Steps
    • Tabs
  • Layout

    • Pane
    • ScrollArea
    • Separator
  • Actions

    • Button
    • IconButton
    • Toggle
    • Toggle group
  • Forms

    • Forms overview
    • Autocomplete
    • Checkbox
    • Combobox
    • Field
    • Fieldset
    • Input
    • Label
    • Number field
    • OTP field
    • Radio group
    • Select
    • Slider
    • Switch
    • Textarea
  • Overlays

    • Dialog
    • Drawer
    • Menu
    • Popover
    • Toast
    • Tooltip
  • Collections

    • Accordion
    • Card
    • Carousel
    • Collapsible
    • DataTable
    • List
    • Marquee
    • Table
  • Status

    • Badge
    • Callout
    • Countdown
    • Empty state
    • Meter
    • Progress
    • Skeleton
    • Sparkline
    • StatTile
  • Media & brand

    • Avatar
    • Icon Tile
    • Image
    • Logo
    • QR code
    • SpotIllustration
  • Text

    • CalendarTile
    • Code
    • DateTime
    • Duration
    • Highlight
    • Mark
    • Prose

Callout

An inline message that sits in the flow of the page, next to the content it's about.

Import

import { Callout } from '@oztix/roadie-components/callout'

Examples

Default

Pass the message as children. With no intent, the callout takes the palette of whatever it sits in.

<Callout>Bring photo ID. Every ticket is checked at the door.</Callout>

Title only and description only

Leave out either one. A title on its own suits a short status; a description on its own suits a sentence.

<div className='grid gap-3'>
  <Callout intent='success' title='Your event is live' />
  <Callout intent='info'>Doors open at 7pm.</Callout>
</div>

Emphasis

subtle is the default. Use normal to sit on a tinted surface, strong for the one message a page can't miss, and subtler for a quiet aside. In a strong callout, give buttons emphasis='normal', because a strong button takes the same fill as the callout.

<div className='grid gap-3'>
  {['strong', 'normal', 'subtle', 'subtler'].map((emphasis) => (
    <Callout key={emphasis} intent='warning' emphasis={emphasis} title={emphasis}>
      Only 20 tickets left at this price.
    </Callout>
  ))}
</div>

Intents

info, success, warning and danger each bring a status icon. Other intents colour the callout without one.

<div className='grid gap-3'>
  <Callout intent='info' title='Doors open at 7pm'>
    The support act starts at 8pm at The Paperbark Room.
  </Callout>
  <Callout intent='success' title='Your event is live'>
    Tickets for Lantern Festival are on sale now.
  </Callout>
  <Callout intent='warning' title='Only 20 tickets left at this price'>
    The next release is $10 more.
  </Callout>
  <Callout intent='danger' title='Payment failed'>
    Update your card to keep your booking.
  </Callout>
</div>

Composition

Build the callout from parts when it needs actions or a rich body. Callout.Icon with no children shows the intent's icon.

<Callout intent='danger'>
  <Callout.Icon />
  <Callout.Title>Payment failed</Callout.Title>
  <Callout.Description>
    Update your card to keep your booking for Saltwater Sessions.
  </Callout.Description>
  <Callout.Actions>
    <Button size='sm'>Update card</Button>
    <Button size='sm'>View booking</Button>
  </Callout.Actions>
</Callout>

With actions

Actions sit below the text in a narrow callout and move beside it once there's 32rem of room inside the callout. The callout measures itself, so it lays out the same in a sidebar as on a phone.

<div className='grid gap-3'>
  <div className='max-w-sm'>
    <Callout intent='warning'>
      <Callout.Icon />
      <Callout.Title>Only 20 tickets left at this price</Callout.Title>
      <Callout.Description>The next release is $10 more.</Callout.Description>
      <Callout.Actions>
        <Button size='sm'>Buy now</Button>
      </Callout.Actions>
    </Callout>
  </div>
  <Callout intent='warning'>
    <Callout.Icon />
    <Callout.Title>Only 20 tickets left at this price</Callout.Title>
    <Callout.Description>The next release is $10 more.</Callout.Description>
    <Callout.Actions>
      <Button size='sm'>Buy now</Button>
    </Callout.Actions>
  </Callout>
</div>

With dismiss

onDismiss adds a dismiss button. You own the visibility, so stop rendering the callout in the handler, and remember the choice if it should stay gone.

function Example() {
  const [open, setOpen] = useState(true)
  if (!open) {
    return <Button onClick={() => setOpen(true)}>Show again</Button>
  }
  return (
    <Callout intent='info' title='Doors open at 7pm' onDismiss={() => setOpen(false)}>
      Entry to Harbour Lights is through the side gate on Beach Road.
    </Callout>
  )
}

render(<Example />)

With a custom icon

Pass icon to the short form, or children to Callout.Icon. Pass icon={null} for no icon.

<div className='grid gap-3'>
  <Callout intent='brand' icon={<TicketIcon weight='bold' />} title='Your tickets are in your wallet'>
    Show them at the gate from your phone.
  </Callout>
  <Callout intent='info' icon={null}>
    Doors open at 7pm.
  </Callout>
</div>

Guidelines

Callout or Toast

Only 20 tickets left at this price

The next release is $10 more.

Do

Use a callout for something that stays true while the page is open, next to the content it's about.

Saved

Your changes were saved.

Don’t

Don't use a callout to confirm an action that just happened. Use a Toast, which comes and goes on its own.

Say what to do next

Payment failed

Update your card to keep your booking.

Do

Lead with what happened and follow with what to do. Keep it to a sentence or two.

Error

Something went wrong.

Don’t

Don't write a vague title. It tells people something is wrong without telling them what.

Keep strong callouts rare

Do

Use one strong callout at most on a page, for the message nobody can miss.

Don’t

Don't stack several callouts. When everything stands out, nothing does. Fold related messages into one.

Accessibility

  • A callout that is on the page when it loads has no live role. Screen readers read it in order, like the rest of the content.
  • For a callout you insert after something happens, add role='status' to announce it politely, or role='alert' to interrupt, only for errors that block the task. Some screen readers only announce changes inside a live region that was already on the page, so for a message that must be heard, keep an empty role='status' wrapper mounted and render the callout into it.
  • The title is a paragraph by default. Make it a heading at the level the page needs with render, e.g. <Callout.Title render={<h3 />}>.
  • The icon is decorative. The intent is only colour and an icon, so the title or description must say what kind of message it is.
  • The dismiss button is named "Dismiss". Change it with dismissLabel. When the callout goes, move focus somewhere sensible so it isn't lost.

API reference

Callout

intent"neutral" | "brand" | "brand-secondary" | "accent" | "danger" | "success" | "warning" | "info"

Palette, and the default icon for `info`, `success`, `warning` and `danger`. Omit to inherit from an ancestor.

emphasis"strong" | "normal" | "subtle" | "subtler"

Defaults to 'subtle'.

titleReactNode

Short form: renders the title, the intent's icon and the children as the description.

iconReactNode

Short form only: replaces the intent's icon. Pass `null` for none.

onDismiss(() => void)

Shows a dismiss button. You own the visibility: stop rendering the callout here.

dismissLabelstring

Defaults to 'Dismiss'.

Callout.Actions

Buttons or links. They sit below the text in a narrow callout and beside it in a wide one.

No additional props. It forwards all standard HTML attributes to the underlying element.

Callout.Description

The body. A `div`, so it can hold paragraphs, links and lists.

No additional props. It forwards all standard HTML attributes to the underlying element.

Callout.Icon

The intent's status icon. Pass children to use your own.

No additional props. It forwards all standard HTML attributes to the underlying element.

Callout.Title

renderRoadieRenderProp

Make the title a heading at the level the page needs, e.g. `render={<h3 />}`. Defaults to `<p>`.

Previous page← BadgeNext pageCountdown →