component — date & time
Day View
One day on a time axis, Outlook-style: hours down the side, an all-day band across the top, overlapping meetings packed side by side, and a marker on the current time. Events carry a ZonedDateTime, so the zone the grid is drawn in is never guessed.
- calendar
- day
- agenda
- events
- schedule
- outlook
07 examples
Default
One day, with the toolbar above it. Overlapping meetings are packed into side-by-side columns, and a block widens into any column free beside it.
Working hours
startHour and endHour cut the axis down to the part of the day anyone looks at; hourHeight decides how much room an hour gets.
Two calendars
Events take their colour from the calendar that owns them. CalendarLegend names the hues, so colour is never the only thing telling them apart.
The legend over the grid
A day is one column, so a legend on its own line costs the grid a line it could have spent on hours. Over the grid it costs nothing — and because an event is then behind it, it takes variant="overlay": the same row on an elevated, blurred surface. Which corner is free is a question about your day, so the placement is a class and not a prop; Week View's gallery walks through the others.
All-day and overnight
An all-day event sits in the band above the grid. An overnight shift stays on the grid and is cut at midnight — its block is cut square where it continues.
Jumping to another day
The heading is a button opening a day grid, which is the default: without it the only way to a day three weeks out is Today or one chevron press at a time. labelVariant="static" turns it back into plain text for a view whose heading is not somewhere to jump from.
Press the heading. The day you pick is reported through onDateChange — the view owns no date here, this state does.
Selection
selectedEventId and onSelectionChange make the selection yours; clicking the selected event again clears it. onEventClick fires on every activation if you only want the click.
Click an event — it reports through onSelectionChange.
source
day-view.tsxCopy this into your project. Resolve its dependencies from the registryDependencies in the component's API entry.
"use client"
import type { CalendarDate } from "@internationalized/date"
import {
type CalendarEvent,
type CalendarGridViewProps,
CalendarShell,
DEFAULT_CALENDAR_TIME_ZONE,
} from "@/components/calendar-shell"
import {
calendarRangeLabel,
type CalendarToolbarLabelVariant,
CalendarToolbar,
type CalendarViewName,
type CalendarViewOption,
useCalendarLocale,
useCalendarNavigation,
} from "@/components/calendar-toolbar"
import { cn } from "@/lib/utils"
/**
* DayView — quebi design system
*
* One day on a time axis, Outlook-style: the hours down the left, an all-day
* band across the top for calendars that have all-day events, overlapping
* meetings packed side by side, and a marker on the current time. Events carry
* `ZonedDateTime` and the view carries the zone it is drawn in, so a meeting
* booked in another zone lands on the right hour here rather than on the hour
* the reader's laptop happens to think it is.
*
* Display and selection only — there is no drag to create, move or resize. See
* the note in `CalendarShell`, which does the drawing; this file decides the day
* and wires the toolbar to it.
*
* `DayView` and `WeekView` are the same grid with a different number of columns,
* and they are two components rather than one prop because the question that
* picks between them is the one a reader asks — "am I looking at a day or a
* week?" — and because their toolbars step by different amounts.
*/
export interface DayViewProps<E extends CalendarEvent = CalendarEvent>
extends CalendarGridViewProps<E> {
/** The day on show. Controlled. */
date?: CalendarDate
/** The initial day. Defaults to today in `timeZone`; pin it on a prerendered route. */
defaultDate?: CalendarDate
onDateChange?: (date: CalendarDate) => void
/** Draw the toolbar above the grid. Default true. */
showToolbar?: boolean
/** Highlight a view switch and report presses on it — for a page hosting all four. */
view?: CalendarViewName
views?: readonly CalendarViewOption[]
onViewChange?: (view: CalendarViewName) => void
/** Replace the heading the toolbar shows. */
label?: React.ReactNode
/** The toolbar's date label as a picker that jumps to any day, or as plain
* text. Default "picker". */
labelVariant?: CalendarToolbarLabelVariant
}
export function DayView<E extends CalendarEvent = CalendarEvent>({
date,
defaultDate,
onDateChange,
showToolbar = true,
view,
views,
onViewChange,
label,
labelVariant = "picker",
timeZone = DEFAULT_CALENDAR_TIME_ZONE,
locale: localeProp,
className,
...shell
}: DayViewProps<E>) {
const locale = useCalendarLocale(localeProp)
const navigation = useCalendarNavigation({
date,
defaultDate,
onDateChange,
step: { days: 1 },
timeZone,
})
const days = [navigation.date]
return (
<div data-slot="day-view" className={cn("flex w-full flex-col gap-3", className)}>
{showToolbar ? (
<CalendarToolbar
label={label ?? calendarRangeLabel(days, { locale, timeZone })}
labelVariant={labelVariant}
date={navigation.date}
onDateChange={navigation.goTo}
view={view}
views={views}
onViewChange={onViewChange}
onPrevious={navigation.goToPrevious}
onNext={navigation.goToNext}
onToday={navigation.goToToday}
/>
) : null}
<CalendarShell {...shell} days={days} locale={locale} timeZone={timeZone} />
</div>
)
}