UI.MD

Week Schedule

A calendar week: seven days on an hour grid, with events placed and sized by their times, an all-day row and a line at the current time.

Installation

$
npx shadcn@latest add https://ui.mattdowney.com/r/week-schedule.json

Usage

import { WeekSchedule, type WeekScheduleEvent } from "@/components/ui/week-schedule"

Examples

Default

Click an event for its details in a popover beside it. Pass onWeekChange for Today, previous and next. Below 768px of its own width it becomes an agenda list by day.

October 2026

  1. Sunday, October 4

  2. Monday, October 5

  3. Tuesday, October 6

    Today
  4. Wednesday, October 7

  5. Thursday, October 8

  6. Friday, October 9

  7. Saturday, October 10

Working hours

A Monday start and an 8am to 7pm grid, which fits without scrolling. Events outside the hours are cut at the edge.

October 2026

  1. Monday, October 5

  2. Tuesday, October 6

    Today
  3. Wednesday, October 7

  4. Thursday, October 8

  5. Friday, October 9

  6. Saturday, October 10

  7. Sunday, October 11

    Nothing scheduled

API Reference

PropTypeDefaultDescription
week*Date-Any date inside the week to show.
events*WeekScheduleEvent[]-{ id, title, start, end?, allDay?, meta?, description?, tone? }. description shows only in the event's popover. A timed event's end defaults to 30 minutes after start; an all-day event's end is its last day, inclusive. tone is a category tint (accent, success, warning, destructive, neutral), so put any meaning it carries in the title or meta too.
weekStartsOn0 to 60First day of the week. 0 is Sunday, 1 is Monday.
startHournumber0First hour on the grid.
endHournumber24Hour the grid stops at.
scrollToHournumber8Hour scrolled to the top when the grid opens.
nowDate-Pins the current time. Leave it out to follow the clock; the today marker and now line appear after load.
localestring"en-US"Formats day names and times.
timeZonestring-The zone to draw the week in, e.g. "America/New_York". Pass it on any server-rendered page: without it the server draws in its own zone and the browser in the viewer's, and the first render is thrown away.
selectedIdstring-Marks the event whose detail you have open elsewhere, such as your own Sheet. An accent ring, so selecting moves nothing.
onEventClick(event) => void-Called with an event when it is clicked, alongside its popover.
eventDetailsbooleantrueClicking an event opens a popover beside it with its time, meta and description. Set it to false to open your own Sheet from onEventClick; with neither, events are plain content.
onWeekChange(week: Date) => void-Adds Today, previous and next to the header, and is called with a date in the new week.
labelstring-Names the week for screen readers. Defaults to "Week of" and the first day.
labelsPartial<{ today, allDay, empty, previousWeek, nextWeek, weekOf, to }>-The component's own words, for a page in another language. Pair with locale, which formats the dates and times.