Moltenship Time
Views

Month

A month grid with multi-day bars and a "+N more" popover.

Live, in your time zone. Drag to move, resize or create events.

Try it in the live demo: pick Month in the view switcher.

createMonthView shows every week that touches the month, starting on weekRules.firstDay. Most months need five rows; some need four or six.

Add it

Copy registry/month-view into your app (it uses shadcn's popover), along with the theme and registry/calendar, as described in UI source. Then register the view:

import { createMonthView } from "@/components/calendar/month-view/month-view";

export const Calendar = createCalendar<Meeting>()({
  eventAdapter,
  views: [createMonthView<Meeting>({ getEventColor: (meeting) => meeting.color })],
});

The view is named month. Previous and Next move by one month.

Anatomy

MonthView renders the parts below. The view builds them itself from its projection, so they're not parts you compose: to change one, edit it in the registry/month-view files you copied. The tree shows where each part lives.

  1. Month viewMonthView
  2. Weekday header
  3. Week rowMonthWeekRow
  4. Day outside the monthinMonth
  5. Todayaria-current="date"
  6. Day celldata-date
  7. Date numberDateButton
  8. Event chipMonthEvent
  9. Multi-day barbar
  10. ContinuationendsAfter
  11. +N moreMoreEvents
Rendered by MonthView
MonthView                        month-view.tsx
├── Weekday header
└── MonthWeekRow                 month-week.tsx, one per week
    ├── Day cell                 data-date
    │   └── DateButton           aria-current="date" on today
    ├── MonthEvent               month-event.tsx
    └── MoreEvents               "+N more" and its popover

A bar is a MonthEvent with bar set. startsBefore and endsAfter mark the ends that continue into another week, and days with inMonth: false are muted.

Options

Prop

Type

What it shows

  • Days: weekday names across the top. Days outside the month are muted, today's date sits in a filled circle, and the first of each month reads "Oct 1".
  • Multi-day and all-day events are bars across the days they cover. A bar that continues into the previous or next week ends with a chevron. Timed bars start with their start time.
  • Single-day timed events show a colored dot, the start time, and the title. On narrow screens they become small tinted blocks.
  • "+N more": rows grow to fill the available height, at least 80px each, and show as many events as fit. The rest collapse into "+N more", which opens a popover with the day's events.
  • Clicking a date number opens that day in the view named day. Register a day view so the click has somewhere to go.
  • Editing: with onEventChange on Root, drag an event to another day (timed events keep their time), and drag across days to create an all-day event. See Interactions.
  • Changes being saved: events with a pending change get aria-busy and render at 60% opacity.

Keyboard

Tab into the preview above, or click a day, and try these keys. The Accessibility page has the full map and what a screen reader hears.

FocusKeyEffect
A day← →Previous or next day
A day↑ ↓Same weekday a week earlier or later
A dayHome, EndFirst or last day of the week
A dayPage Up, Page DownSame day in the previous or next month
A dayEnterGo into the day's events. ↑ ↓ walk them, and Escape goes back to the day
A dayShift+EnterOpen the day in the day view
A daySpaceStart an all-day event there. Arrow keys extend it, and Enter saves it
An eventSpacePick it up. Arrow keys move it by days, Enter saves, and Escape cancels
An eventShift+SpacePick up its end to resize it by days. Shift+Space again switches to its start

Events behind "+N more" are reachable too: while focus is on one, its week shows every event.

Markup for interactions

The view connects the pointer layer for you. If you change its markup, keep the attributes it reads: each day cell holds an element with data-date underneath its events, and each event is a <button> with data-event-id. The events sit beside that element, not inside it, so a drag over a bar still finds the day under the pointer.

Edit on GitHub

Last updated on

On this page