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.

Mi7
01 Uhr
02 Uhr
03 Uhr
04 Uhr
05 Uhr
06 Uhr
07 Uhr
08 Uhr
09 Uhr
10 Uhr
11 Uhr
12 Uhr
13 Uhr
14 Uhr
15 Uhr
16 Uhr
17 Uhr
18 Uhr
19 Uhr
20 Uhr
21 Uhr
22 Uhr
23 Uhr

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.

Mi7
09 Uhr
10 Uhr
11 Uhr
12 Uhr
13 Uhr
14 Uhr
15 Uhr
16 Uhr
17 Uhr

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.

My calendarTeam
Mi7
09 Uhr
10 Uhr
11 Uhr
12 Uhr
13 Uhr
14 Uhr
15 Uhr
16 Uhr
17 Uhr

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.

Mi7
09 Uhr
10 Uhr
11 Uhr
12 Uhr
13 Uhr
14 Uhr
15 Uhr
16 Uhr
17 Uhr
My calendarTeam

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.

Mi7
all day
09 Uhr
10 Uhr
11 Uhr
12 Uhr
13 Uhr
14 Uhr
15 Uhr
16 Uhr
17 Uhr
18 Uhr
19 Uhr
20 Uhr
21 Uhr
22 Uhr
23 Uhr

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.

Mi7
09 Uhr
10 Uhr
11 Uhr
12 Uhr
13 Uhr
14 Uhr
15 Uhr
16 Uhr
17 Uhr

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.

Mi7
09 Uhr
10 Uhr
11 Uhr
12 Uhr
13 Uhr
14 Uhr
15 Uhr
16 Uhr
17 Uhr

Click an event — it reports through onSelectionChange.

source

day-view.tsx

Copy 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>
  )
}