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

CalendarTile

A two-row tile showing a month and a day.

Import

import { CalendarTile } from '@oztix/roadie-components/calendar-tile'

Examples

Default

<CalendarTile month='NOV' day={27} />

Weekday

Leads with the day of week instead of the month, for schedule lists where a heading already establishes the month.

<div className='flex flex-wrap gap-3'>
  <CalendarTile month='NOV' day={27} />
  <CalendarTile weekday='FRI' day={27} />
</div>

Border radius

Defaults to rounded-xl, matching Card. Override with any Tailwind radius class. Use rounded-none for a tile that bleeds to a card edge rather than floating inside it.

<div className='flex flex-wrap gap-3'>
  <CalendarTile month='NOV' day={27} className='rounded-none' />
  <CalendarTile month='NOV' day={27} className='rounded-md' />
  <CalendarTile month='NOV' day={27} />
  <CalendarTile month='NOV' day={27} className='rounded-2xl' />
</div>

Emphasis

<div className='flex flex-wrap gap-3'>
  <CalendarTile month='NOV' day={27} emphasis='strong' />
  <CalendarTile month='NOV' day={27} emphasis='normal' />
  <CalendarTile month='NOV' day={27} emphasis='subtle' />
  <CalendarTile month='NOV' day={27} emphasis='subtler' />
</div>

Sizes

<div className='flex flex-wrap items-end gap-3'>
  <CalendarTile month='NOV' day={27} size='sm' />
  <CalendarTile month='NOV' day={27} size='md' />
  <CalendarTile month='NOV' day={27} size='lg' />
</div>

Intents

<div className='flex flex-wrap gap-3'>
  <CalendarTile month='NOV' day={27} intent='accent' />
  <CalendarTile month='NOV' day={27} intent='neutral' />
  <CalendarTile month='NOV' day={27} intent='success' />
  <CalendarTile month='NOV' day={27} intent='danger' />
</div>

Composition

The tile abbreviates hard. It is paired with a line that carries the full date. Where the tile is the only date on a card, that line is required, not optional.

<div className='flex items-center gap-3'>
  <CalendarTile month='NOV' day={27} />
  <div className='min-w-0'>
    <p className='text-sm text-strong'>Willow Bend Festival</p>
    <p className='text-sm text-subtle'>Fri 27 Nov 2026 · Kilcoy, QLD</p>
  </div>
</div>

Guidelines

Strings come from formatGlyph in @oztix/roadie-core/datetime. It resolves them in the venue's timezone. Building them from new Date() at the call site renders the wrong day for anyone not standing at the venue. See Date and time.

import { formatGlyph } from '@oztix/roadie-core/datetime'
const glyph = formatGlyph(event.startsAt, {
timeZone: event.venue.timeZone
})

The tile carries a month and a day and never a year. A three-row tile is cramped at 48px. The year is not what anyone scans a tile for. Whatever sits beside it owns the full date.

Without React

This is the one component with a CSS twin. A server-rendered template uses the matching calendar-tile utility from @oztix/roadie-core/css, so both render an identical tile.

<div class="calendar-tile emphasis-subtle intent-accent" aria-hidden="true">
<span class="calendar-tile-top">NOV</span>
<span class="calendar-tile-day">27</span>
</div>

The strings still come from formatGlyph, or from a server-side formatter following the same rules. The markup is the easy half. Resolving the day in the venue's timezone is the half that goes wrong.

Accessibility

The rows are abbreviations, so they are never the accessible name. Without a label the tile is marked aria-hidden and announces nothing at all, which is right when a date line beside it already says the date.

Pass dateTime and the tile renders as a time element instead of a plain box. Do that only when the tile is the only date in its region. Where a date line sits beside it, that line owns the time element. Two of them publish the same instant twice, and a screen reader reads it twice.

import {
formatFull,
formatGlyph,
formatMachine
} from '@oztix/roadie-core/datetime'
const glyph = formatGlyph(startsAt, { timeZone })
const machine = formatMachine(startsAt, { timeZone })
const full = formatFull(startsAt, { timeZone })
glyph && machine && full ? (
<CalendarTile
month={glyph.month}
day={glyph.day}
dateTime={machine}
label={full}
/>
) : null

Take month and day off the glyph rather than spreading it. It also carries weekday, and the tile prefers a weekday over a month when both arrive, so a spread renders FRI 27 where NOV 27 was meant.

Guard all three together. Every formatter returns string | null for a zone it cannot resolve, and a guard on one does not narrow the others.

  • Pass label with the full date when the tile is the only date in its region. It renders as role='img' with that accessible name.
  • Omit label when a neighbouring line already states the date. The tile is then marked aria-hidden, so the date is announced once rather than twice.

API reference

CalendarTile

daystring | number
Required

Day of the month, e.g. `27`.

labelstring

The full date, for assistive tech. The tile abbreviates hard, so without this a labelless tile is `aria-hidden` and announces nothing.

dateTimestring

Machine-readable value from `formatMachine`. Setting it renders a `<time>` element instead of a plain box, so the rest of the props are typed against `time` rather than `div`. Set it only when the tile is the **only** date in its region. If a date line sits beside it, that line owns the `<time>`, and two of them would publish the same instant twice.

intent"neutral" | "brand" | "brand-secondary" | "accent" | "danger" | "success" | "warning" | "info" | null
emphasis"strong" | "normal" | "subtle" | "subtler" | null
size"sm" | "md" | "lg" | null
monthstring

Short month, e.g. `NOV`. Ignored when `weekday` is set.

weekdaystring

Short weekday, e.g. `FRI`. Replaces the month in the top row.

Previous page← SpotIllustrationNext pageCode →