ChronousDocumentation

Examples

Agenda

A flat list of days with the events under each, and empty days left out.

An agenda

Two weeks as a flat list: one row per day that has something in it, with the all-day entries above the timed ones. There is no grid here at all, so as turns the whole thing into a real ul.

Running here

The component

Agenda.tsx
import { createCalendarComponents } from '@midstem/chronous-react'
import type { CalendarRange, EventInput } from '@midstem/chronous-react'

type EventData = { title: string }

const Calendar = createCalendarComponents<EventData>()

const RANGE: CalendarRange = {
  view: 'agenda',
  dayCount: 14,
  currentDate: '2026-03-18',
  timeZone: 'Europe/Kyiv',
}

const EVENTS: EventInput<EventData>[] = [
  {
    id: 'offsite',
    start: '2026-03-18',
    end: '2026-03-20',
    data: { title: 'Offsite' },
  },
  {
    id: 'standup',
    start: '2026-03-18T09:00',
    duration: 'PT15M',
    recurrence: { rule: 'FREQ=WEEKLY;BYDAY=MO,WE,FR' },
    data: { title: 'Standup' },
  },
  {
    id: 'review',
    start: '2026-03-19T14:00',
    end: '2026-03-19T15:30',
    data: { title: 'Design review' },
  },
]

export const Agenda = (): JSX.Element => (
  <Calendar.Root range={RANGE} events={EVENTS} locale="en-GB">
    <Calendar.AgendaList as="ul" className="agenda">
      <Calendar.AgendaDays as="li" className="agenda-day">
        {({ weekdayLabel, dayLabel, monthLabel }) => (
          <>
            <span className="agenda-date">
              {weekdayLabel} {dayLabel} {monthLabel}
            </span>

            <span className="agenda-events">
              <Calendar.AgendaAllDayEvents as="span" className="agenda-event">
                {({ event }) => `${event.data?.title} · all-day`}
              </Calendar.AgendaAllDayEvents>

              <Calendar.AgendaTimedEvents as="span" className="agenda-event">
                {({ event, timeRangeLabel }) =>
                  `${event.data?.title} · ${timeRangeLabel}`
                }
              </Calendar.AgendaTimedEvents>
            </span>
          </>
        )}
      </Calendar.AgendaDays>
    </Calendar.AgendaList>
  </Calendar.Root>
)

The stylesheet

agenda.css
.agenda {
  margin: 0;
  padding: 0;
  list-style: none;
  color: #d8e5ff;
}

.agenda-day {
  display: flex;
  gap: 16px;
  padding: 12px 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.agenda-date {
  flex: 0 0 120px;
  font-size: 13px;
  font-weight: 600;
}

.agenda-events {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: #8d8da0;
}

Empty days

By default a day with nothing in it is skipped, which is what makes an agenda read as a list rather than as a calendar. Pass showEmptyDays to render the whole span instead.

tsx
import { Calendar } from '@midstem/chronous-react'
import type { CalendarRange } from '@midstem/chronous-react'

const range: CalendarRange = {
  view: 'agenda',
  dayCount: 7,
  currentDate: '2026-03-18',
  timeZone: 'Europe/Kyiv',
}

// Every day in the span, not only the ones that have something in them.
export const Agenda = () => (
  <Calendar.Root range={range} events={[]} locale="en-GB">
    <Calendar.AgendaList as="ul" className="agenda">
      <Calendar.AgendaDays as="li" className="agenda-day" showEmptyDays>
        {({ dayLabel, monthLabel }) => (
          <span className="agenda-date">
            {dayLabel} {monthLabel}
          </span>
        )}
      </Calendar.AgendaDays>
    </Calendar.AgendaList>
  </Calendar.Root>
)

timeRangeLabel is formatted in the calendar’s locale before it reaches you — the same as every other name ending in Label, as Labels describes.