Marble UI
← Components

Event Calendar / Scheduler

Preview: Month

Month and week views of events, formatted in the React Aria locale. Events are buttons (keyboard reachable) labelled with title and time; a month day with more than three events gets a "+N more" button that expands the day in place.

Import

import { EventCalendar } from '@marbleui/ui'

Props

<EventCalendar>

PropTypeDefaultDescription
events *requiredCalendarEvent[]—
classNamestring—
defaultDateDatenew Date()Any date inside the initial month/week.
defaultView'month' | 'week''month'
onEventPress(e: CalendarEvent) => void—
weekStartsOn0 | 11

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitive: React Aria Button. Follow the primitive's docs for the full keyboard map.

Usage notes

EventCalendar displays events in a month grid or a scrolling 24-hour week view, with Today, previous/next and a Month/Week switch. It only shows events; to pick a date use Calendar, and for task schedules use Gantt.

<EventCalendar
  events={[
    { id: 'e1', title: 'Design review', start: new Date(2026, 9, 28, 14), end: new Date(2026, 9, 28, 15, 30), color: 7 },
    { id: 'e2', title: 'Company offsite', start: new Date(2026, 9, 30), end: new Date(2026, 9, 31), allDay: true, color: 4 },
  ]}
  onEventPress={(event) => openEvent(event.id)}
/>
  • Events use JS Dates; color picks slot 1–8 (--chart-1…8). defaultDate and defaultView only set the starting view, and there’s no callback for the visible range, so pass every event you may need. weekStartsOn is 1 (Monday, default) or 0 (Sunday).
  • Each event is a button named by its time and title (not its day). onEventPress fires on click, Enter or Space.
  • Month view shows three events per day, then a “+N more” button that expands the day in place (and “Show less” to collapse it). Week view shows all-day events in a row above the hours (spanning each day they cover) and lays overlapping timed events out side by side. In month view, multi-day events appear only on their start day.
  • Dates and times follow the React Aria locale (LocaleProvider).
Example source · show
import { useMemo, useState } from 'react'
import { EventCalendar, type CalendarEvent } from './event-calendar'

function useEvents() {
  return useMemo(() => {
    const now = new Date()
    const at = (dayOffset: number, h: number, m = 0, dur = 60) => {
      const s = new Date(now.getFullYear(), now.getMonth(), now.getDate() + dayOffset, h, m)
      return { start: s, end: new Date(+s + dur * 60000) }
    }
    const list: CalendarEvent[] = [
      { id: '1', title: 'Standup', ...at(0, 9, 30, 15), color: 1 },
      { id: '2', title: 'Design review', ...at(0, 14, 0, 90), color: 7 },
      { id: '3', title: 'Lunch with Maya', ...at(1, 12, 30, 60), color: 3 },
      { id: '4', title: 'Release v2.4', ...at(2, 16, 0, 30), color: 2 },
      { id: '5', title: 'Planning', ...at(-2, 10, 0, 120), color: 1 },
      { id: '6', title: '1:1 Charles', ...at(3, 11, 0, 30), color: 5 },
      { id: '7', title: 'Offsite', ...at(8, 9, 0, 480), color: 4 },
      { id: '8', title: 'Board update', ...at(-6, 15, 0, 60), color: 8 },
      { id: '9', title: 'Interview', ...at(0, 11, 0, 45), color: 6 },
      { id: '10', title: 'Retro', ...at(0, 16, 30, 45), color: 1 },
    ]
    return list
  }, [])
}

function Month() {
  const events = useEvents()
  const [picked, setPicked] = useState<string | null>(null)
  return (
    <div className="flex w-[52rem] flex-col gap-2">
      <EventCalendar events={events} onEventPress={(e) => setPicked(e.title)} />
      {picked && <span className="text-sm text-fg-muted">Opened: {picked}</span>}
    </div>
  )
}

export const styles = { Month, Week: () => <EventCalendar className="w-[52rem]" events={useEvents()} defaultView="week" /> }

Source: packages/ui/src/event-calendar/event-calendar.tsx

Catalog

Category
date-time
Priority
Pro
Primitive
composed
React Aria
Calendar + GridList