Views
Choose and configure the views with defineViews, from N-day time grids to agenda lists, and format their dates.
A view is a name and a definition: one of three kinds with its options. The calendar shows the
views of views in its switcher, in order, and opens on defaultView (or the first one).
Without views it has defaultViews:
| Name | Definition | Shows |
|---|---|---|
week | timeGrid({ days: 7 }) | seven day columns over a time axis |
day | timeGrid({ days: 1 }) | one day |
month | dayGrid({ unit: 'month' }) | the month in week rows of day cells |
list | list({ unit: 'week' }) | the week's events, grouped by day |
Your own views
defineViews keeps the names you give, so every option that takes a view name is checked against
them:
'use client'
import {
dayGrid,
defineViews,
list,
timeGrid,
type CalendarEventInput,
type ViewName,
} from '@hapio/calendar-react'
import { HapioCalendar } from '@/components/hapio-calendar/hapio-calendar'
// The switcher shows them in this order; the first is the default view.
const views = defineViews({
workWeek: timeGrid({ days: 5, align: 'week', slotMin: '07:00', slotMax: '19:00' }),
threeDays: timeGrid({ days: 3, step: 1 }), // "3 days", moving a day at a time
month: dayGrid({ unit: 'month', weekNumbers: true, maxEvents: 3 }),
agenda: list({ unit: 'month', label: 'Agenda' }),
})
// 'workWeek' | 'threeDays' | 'month' | 'agenda'
type View = ViewName<typeof views>
export function TeamCalendar({
events,
initialView,
}: {
events: readonly CalendarEventInput[]
initialView: View
}) {
return (
<HapioCalendar
views={views}
defaultView={initialView} // a name `views` lacks is a type error
hiddenDays={[7]} // no Sundays, in every view
events={events}
timeZone="Europe/Stockholm"
navLinks={{ day: 'threeDays', week: 'workWeek' }} // where day and week numbers link
className="h-[36rem]"
/>
)
}The switcher labels its views by unit ("Week", "Day", "Month", "List", "3 days") unless a view
has a label, and screen readers hear each radio as "Week view", "Agenda view" and so on. View names are yours and
appear in callbacks (onViewChange, RangeChange.view) and in the root's data-view.
Define views in a client module (or at module scope of a page): a view map whose formats are functions cannot cross from a Server Component to a client component. Only plain data and view names can.
Time grids: timeGrid()
Day columns over a time axis, with an all-day row on top.
days(1 to 31, default 7) andalign:'week'starts onweekStartsOn(the default for 7 days),'day'starts on the date (the default otherwise).stepis how many days Previous and Next move (defaultdays; whole weeks for a week-aligned grid).slotDuration('PT30M'),snapDuration(drags and resizes snap to it; default the slot),slotLabelInterval(default an hour),slotMinandslotMax('00:00'to'24:00'; times past midnight are not supported in 1.0),scrollTime(where the grid starts scrolled, default'06:00').allDaySlot: falseleaves out the all-day row.overlap: 'stack'(default) lets later events overlap earlier ones;'columns'gives overlapping events side by side columns.maxStackcaps the columns and adds a "+N" that opens the hidden events.- The lanes are a wall-clock axis: on the days daylight saving time changes, the hour that does not exist and the hour that happens twice are marked bands. See Time zones.
Day grids: dayGrid()
Week rows of day cells: a month (unit: 'month', the default), a week or a day.
maxEvents: how many rows of events a cell shows before "+N more" opens the rest in a popover.'auto'(the month's default) fits as many as the cell's height allows; a number fixes it, the "+N more" row counting as one;falseshows every event and lets the rows grow.fixedWeekCount(defaulttrue) always shows six weeks;showOtherMonthDays: falseleaves the adjacent months' days empty.weekNumbersadds ISO week numbers; withnavLinksthey link to a week view.- A timed event of one day shows as a dot with its start time; all-day and multi-day events as bars across the cells.
Lists: list()
Events grouped by day, as a list of links and buttons: unit 'day', 'week' (default) or
'month', and showEmptyDays to list days without events too. An event that spans days shows on
each day ("From 22:00", "All day", "Until 11:00"). With no events the list shows
strings.noEvents ("No events to display"), or what renderEmpty renders.
Options for every view
Most time-grid options can also be given to the calendar, for every time grid at once
(slotDuration, snapDuration, slotMin, slotMax, scrollTime, maxStack); a view's own
option wins. The same holds for hiddenDays (ISO weekdays, Monday is 1) and
formats. maxEvents set on the calendar applies to the day grids and caps the time grids'
all-day rows too.
navLinks turns day headers (and week numbers) into links to a day or week view: true picks the
first one-day and seven-day time grids of views, { day, week } names them.
Formats
Every date the calendar shows comes from a format, Intl.DateTimeFormat options in the calendar's
locale and timeZone:
'use client'
import type { CalendarFormats } from '@hapio/calendar-react'
const H24 = { hour: '2-digit', minute: '2-digit', hour12: false } as const
export const formats: Partial<CalendarFormats> = {
// `Intl.DateTimeFormat` options, plus Hapio's flags.
dayHeader: { weekday: 'short', day: 'numeric', omitCommas: true }, // "Thu 22"
eventTime: H24, // "09:00 – 10:30"
slotLabel: H24,
moreTitle: { weekday: 'long', day: 'numeric', month: 'long' },
// A function receives a Temporal value (it needs the global Temporal) and the context.
listDay: (value, { locale }) => value.toLocaleString(locale, { weekday: 'long' }),
}| Format | Where |
|---|---|
title | the toolbar title (formatted as a range) |
dayHeader | column headers |
slotLabel | the time axis |
eventTime | event times |
listDay | a list day's heading |
listDayAlt | a list day's second heading |
moreTitle | the "+N more" popover's heading |
weekNumber | week numbers |
Four flags post-process Intl's output: omitCommas ("Thu, 29 Oct" → "Thu 29 Oct"),
forceCommas, omitZeroMinute ("9:00 AM" → "9 AM") and meridiem ('short', 'narrow' or
false). A function format receives a Temporal.ZonedDateTime (timed) or Temporal.PlainDate
(all-day) and { locale, timeZone }.
Kinds from later versions
renderers maps view kinds to the components that render them. The block renders the three
built-in kinds; a kind your copied files have no renderer for (a view kind added in a later
version, before you update the files) shows UnsupportedView, a short notice
(strings.unsupportedView(label): "The “Timeline” view can’t be shown here."), instead of
breaking. See Upgrading.