super-calendar: React Calendar With Month, Week, and Day Views

Description:

super-calendar is a React calendar component that creates month, week, day, 3-day, custom N-day, and schedule views with event data, date selection, and gesture-driven time grids.

The component uses a virtualized date pager, Reanimated zoom on native, and a separate DOM renderer for standard React web apps.

Preview

super-calendar

Features

  • Renders month, week, day, 3-day, custom N-day, and schedule calendar views.
  • Virtualizes and snap-pages date views across long ranges.
  • Responds to pinch zoom on native and Ctrl or Command plus scroll on web.
  • Accepts application-specific event fields and a custom event component.
  • Handles single-date, multiple-date, and range selection in a scrollable month list.
  • Supports event move, resize, and creation on the week and day grid.
  • Applies light and dark theme presets plus locale-aware date labels.
  • Runs on iOS, Android, and web through separate React Native and DOM renderers.

How To Use It

Install the Native Calendar

Import Reanimated, Worklets, Gesture Handler, Legend List, and date-fns.

npm install @super-calendar/native
npm install react-native-reanimated react-native-worklets react-native-gesture-handler @legendapp/list date-fns

Render a Controlled Calendar

Calendar keeps the visible date controlled through the date prop. Echo onChangeDate into that state so page changes and today alignment follow the current value.

import { useState } from "react";
import { Calendar, type CalendarEvent } from "@super-calendar/native";
type ScheduleEvent = {
  id: string;
  color: string;
  team: string;
};
const events: CalendarEvent<ScheduleEvent>[] = [
  {
    id: "design-review",
    color: "#7C3AED",
    team: "Product",
    title: "Design review",
    start: new Date(2026, 7, 5, 9, 30),
    end: new Date(2026, 7, 5, 10, 30),
  },
  {
    id: "release-window",
    color: "#0891B2",
    team: "Engineering",
    title: "Release window",
    start: new Date(2026, 7, 6, 14, 0),
    end: new Date(2026, 7, 6, 16, 0),
  },
];
export function ScheduleCalendar() {
  const [date, setDate] = useState(new Date(2026, 7, 1));
  const [mode, setMode] = useState<"month" | "week" | "day">("week");
  // Keep page changes in the controlled date state.
  return (
    <Calendar
      mode={mode}
      date={date}
      events={events}
      weekStartsOn={1}
      onChangeDate={setDate}
      onPressEvent={(event) => console.log(event.title)}
      onPressDay={(day) => {
        setDate(day);
        setMode("day");
      }}
    />
  );
}

Render Custom Event Cards

renderEvent receives a React component. Define it outside the screen component or memoize it so the calendar can reuse the inner views across renders.

import { Pressable, Text } from "react-native";
import { Calendar, type RenderEventArgs } from "@super-calendar/native";
type ScheduleEvent = {
  id: string;
  color: string;
  team: string;
};
function EventCard({ event, onPress, isAllDay }: RenderEventArgs<ScheduleEvent>) {
  return (
    <Pressable
      onPress={onPress}
      style={{ flex: 1, padding: 6, borderRadius: 8, backgroundColor: event.color }}
    >
      {/* Keep the content inside the event box supplied by the calendar. */}
      <Text style={{ color: "#FFFFFF", fontWeight: "700" }}>{event.title}</Text>
      <Text style={{ color: "#FFFFFF" }}>{isAllDay ? "All day" : event.team}</Text>
    </Pressable>
  );
}
// Reuse the events array from the controlled calendar example.
<Calendar
  mode="week"
  date={new Date(2026, 7, 3)}
  events={events}
  renderEvent={EventCard}
/>

Add Dragging and Event Creation

Pass onDragEvent to enable move and resize interactions. The handler receives the event plus its proposed start and end dates. Return false to reject a placement.

<Calendar
  mode="week"
  date={date}
  events={events}
  dragStepMinutes={30}
  eventOverlap={false}
  onDragEvent={(event, start, end) => {
    if (event.team === "Locked") return false;
    setEvents((current) =>
      current.map((item) =>
        item.id === event.id ? { ...item, start, end } : item,
      ),
    );
  }}
  onCreateEvent={(start, end) => {
    setEvents((current) => [
      ...current,
      {
        id: String(Date.now()),
        color: "#EA580C",
        team: "Operations",
        title: "New appointment",
        start,
        end,
      },
    ]);
  }}
/>

Add Recurring Events

The calendar accepts recurrence rules through event data. Expand the rules for the visible range before passing the result to Calendar.

import { Calendar, expandRecurringEvents } from "@super-calendar/native";
const recurring = [
  {
    id: "support-checkin",
    title: "Support check-in",
    start: new Date(2026, 7, 3, 11, 0),
    end: new Date(2026, 7, 3, 11, 30),
    recurrence: {
      freq: "weekly",
      weekdays: [1, 3],
      count: 12,
    },
  },
];
const visibleEvents = expandRecurringEvents(
  recurring,
  new Date(2026, 7, 1),
  new Date(2026, 7, 31),
);
<Calendar mode="month" date={new Date(2026, 7, 1)} events={visibleEvents} />;

Create a Date Range Picker

Use MonthList for date picking. The paged month view is intended for event browsing. useDateRange owns the range state machine.

import { useMemo, useState } from "react";
import { MonthList, useDateRange } from "@super-calendar/native";
export function BookingDatePicker() {
  const [month, setMonth] = useState(new Date(2026, 7, 1));
  const minDate = useMemo(() => new Date(), []);
  const { range, onPressDate, selectRange } = useDateRange({ minDate });
  return (
    <MonthList
      date={month}
      weekStartsOn={1}
      selectedRange={range ?? undefined}
      minDate={minDate}
      isDateDisabled={(day) => day.getDay() === 0}
      onPressDay={onPressDate}
      onSelectDrag={selectRange}
      onChangeVisibleMonth={setMonth}
    />
  );
}

Use the Web or Headless Packages

Use @super-calendar/dom for a plain React DOM app. It exports MonthView, MonthList, TimeGrid, and useDateRange. It uses inline styles through a theme prop.

npm install @super-calendar/dom react react-dom @legendapp/list date-fns
import { MonthList, TimeGrid, useDateRange } from "@super-calendar/dom";

Use @super-calendar/core when the application owns the renderer. Its exports include buildMonthGrid, useMonthGrid, useDateRange, selection helpers, event layout, and date utilities.

npm install @super-calendar/core react date-fns
import { buildMonthGrid, nextDateRange } from "@super-calendar/core";

Calendar API

Groupprops
Dataevents, date, mode, numberOfDays, weekStartsOn, weekdayFormat, timeZone
NavigationonChangeDate, onChangeDateRange, freeSwipe
RenderingrenderEvent, eventAccessibilityLabel, renderCustomDateForMonth, eventCellStyle, calendarCellStyle, businessHours, renderBusinessHours, renderTimeGridHeader, renderHeaderForMonthView, headerComponent, keyExtractor
InteractiononDragEvent, onDragStart, onCreateEvent, dragStepMinutes, showDragHandle, eventStartEditable, eventDurationEditable, eventOverlap, onPressEvent, onPressCell, onPressDay, onPressMore
SelectionselectedDates, selectedRange, onSelectDrag, minDate, maxDate, isDateDisabled
DisplayscrollOffsetMinutes, hourHeight, timeslots, ampm, showNowIndicator, showAllDayEventCell, allDayLabel, highlightWeekends, maxVisibleEventCount, theme, classNames, styles

Alternatives and Related Resources

FAQs

Q: Which package should I install for a React DOM calendar?
A: Install @super-calendar/dom with react, react-dom, @legendapp/list, and date-fns. Import MonthView, MonthList, or TimeGrid from @super-calendar/dom.

Q: Why does paging stop following the current date?
A: Keep date controlled and pass the new value from onChangeDate back into Calendar.

Q: Can I use only the date picker?
A: Yes. Import MonthList, useDateRange, and useMonthGrid from @super-calendar/native/picker. Install the picker peers listed in the package documentation.

Q: How do I block past dates or specific weekdays?
A: Pass minDate, maxDate, or isDateDisabled to MonthList and pass the same range constraints to useDateRange.

Q: Why do custom event cards remount during calendar updates?
A: Keep the renderEvent component and interaction callbacks stable. Define the renderer at module scope or wrap callbacks in useCallback.

Add Comment