Events data

Event data shapes and callback payloads for @mantine/schedule

Overview

All @mantine/schedule components accept events through the events prop. Each event is typed as ScheduleEventData and can be one of three shapes:

  • One-off event – a regular event without recurrence
  • Recurring series event – a source event that expands into multiple occurrences
  • Recurring override event – an event that replaces a single occurrence of a series

All three variants share a common set of base fields described in ScheduleEventBase.

ScheduleEventBase

import type { DateTimeStringValue, EventPayload } from '@mantine/schedule';
import type { MantineColor } from '@mantine/core';

interface ScheduleEventBase<Payload extends EventPayload = EventPayload> {
  /** Unique event id, used for key and identification */
  id: string | number;

  /** Event title, displayed in month, week and day views */
  title: string;

  /** Event start date/time */
  start: Date | DateTimeStringValue;

  /** Event end date/time */
  end: Date | DateTimeStringValue;

  /** Event background color. Key of `theme.colors` or any valid CSS color. */
  color: MantineColor;

  /** Event variant, default is `'light'` */
  variant?: 'filled' | 'light';

  /** Event display mode. Background events render as full-width blocks behind regular
   *  events, non-interactive unless `withInteractiveBackgroundEvents` is set on the view.
   *  @default 'default' */
  display?: 'default' | 'background';

  /** Additional event data, defined by the user, not used internally by the library */
  payload?: Payload;
}

start and end accept either a Date instance or a string in YYYY-MM-DD HH:mm:ss format (the DateTimeStringValue type used by all Mantine date components).

ScheduleSingleEventData

A one-off event without recurrence. This is the most common shape:

import type { ScheduleSingleEventData } from '@mantine/schedule';

const event: ScheduleSingleEventData = {
  id: 'meeting-1',
  title: 'Team sync',
  start: '2024-01-15 10:00:00',
  end: '2024-01-15 11:00:00',
  color: 'blue',
};

ScheduleRecurringSeriesEventData

A source event for a recurring series. Adds a recurrence field with an RFC 5545 recurrence rule:

import type { ScheduleRecurringSeriesEventData } from '@mantine/schedule';

const series: ScheduleRecurringSeriesEventData = {
  id: 'weekly-planning',
  title: 'Weekly planning',
  start: '2024-01-15 10:00:00',
  end: '2024-01-15 11:00:00',
  color: 'blue',
  recurrence: {
    rrule: 'FREQ=WEEKLY;BYDAY=MO;COUNT=12',
    exdate: ['2024-02-12 10:00:00'],
    dtstart: '2024-01-15 10:00:00',
  },
};

The recurrence object has the following shape:

interface ScheduleRecurrenceData {
  /** Recurrence rule string, for example: `FREQ=WEEKLY;BYDAY=MO,WE` */
  rrule: string;

  /** Exception datetimes in `YYYY-MM-DD HH:mm:ss` or valid date string format */
  exdate?: DateTimeStringValue[];

  /** Optional explicit series start datetime */
  dtstart?: DateTimeStringValue;
}

See the Recurring events guide for more details on recurrence rules and series expansion.

ScheduleRecurringOverrideEventData

An override event replaces a single generated occurrence from a series:

import type { ScheduleRecurringOverrideEventData } from '@mantine/schedule';

const override: ScheduleRecurringOverrideEventData = {
  id: 'weekly-planning-override',
  title: 'Weekly planning (moved)',
  start: '2024-01-17 16:00:00',
  end: '2024-01-17 17:00:00',
  color: 'grape',
  recurringEventId: 'weekly-planning',
  recurrenceId: '2024-01-15 10:00:00',
};
  • recurringEventId – id of the parent series event
  • recurrenceId – original occurrence datetime in YYYY-MM-DD HH:mm:ss format

EventPayload

Use the payload field to attach your own data to events. It is not used by the library, you can read it in callbacks and in custom event renderers:

import type { ScheduleEventData } from '@mantine/schedule';

interface MyEventPayload {
  description: string;
  attendees: string[];
  location?: string;
}

const event: ScheduleEventData<MyEventPayload> = {
  id: 'meeting-1',
  title: 'Team sync',
  start: '2024-01-15 10:00:00',
  end: '2024-01-15 11:00:00',
  color: 'blue',
  payload: {
    description: 'Weekly planning meeting',
    attendees: ['Alice', 'Bob'],
    location: 'Conference room A',
  },
};

EventPayload is Record<PropertyKey, any>. Pass your own payload type as a generic argument: ScheduleEventData<MyPayload>.

Recurring instance metadata

Each event generated from a recurring series has a recurringInstance object. It is added by the library, read it in callbacks and custom renderers to distinguish generated occurrences from regular events:

interface RecurringInstanceMeta {
  /** If true, event is generated from recurrence rule */
  isRecurringInstance: boolean;

  /** Parent series event id */
  recurringEventId: string | number;

  /** Original occurrence datetime key */
  recurrenceId: DateTimeStringValue;

  /** Original occurrence dates before any drag/drop updates */
  originalStart: DateTimeStringValue;
  originalEnd: DateTimeStringValue;
}

Example of reading the metadata in onEventClick:

<Schedule
  events={events}
  onEventClick={(event) => {
    if (event.recurringInstance?.isRecurringInstance) {
      console.log('Clicked generated occurrence of', event.recurringInstance.recurringEventId);
    } else {
      console.log('Clicked regular event', event.id);
    }
  }}
/>

Callback payloads

onEventClick

Called when an event is clicked in any view:

onEventClick?: (
  event: ScheduleEventData,
  e: React.MouseEvent<HTMLButtonElement>
) => void;

onEventDrop

Called when an event is dropped after a drag (requires withEventsDragAndDrop):

onEventDrop?: (data: {
  eventId: string | number;
  newStart: DateTimeStringValue;
  newEnd: DateTimeStringValue;
  event: ScheduleEventData;
}) => void;
  • eventId – id of the dropped event, same as event.id. For generated recurring occurrences it is the occurrence id ("<seriesId>::<recurrenceId>"), not the series id. Use event.recurringInstance?.recurringEventId to get the series id.
  • newStart / newEnd – new datetime values in YYYY-MM-DD HH:mm:ss format.

onEventResize

Called when an event is resized by dragging its top or bottom edge (requires withEventResize):

onEventResize?: (data: {
  eventId: string | number;
  newStart: DateTimeStringValue;
  newEnd: DateTimeStringValue;
  event: ScheduleEventData;
}) => void;

The payload has the same shape as onEventDrop, including the caveat about eventId for generated recurring instances.

onEventDragStart / onEventDragEnd

Called when an event drag starts or ends:

onEventDragStart?: (event: ScheduleEventData) => void;
onEventDragEnd?: () => void;

onEventDragEnd is called both for successful drops and for cancelled drags – use onEventDrop if you need the new position.

onTimeSlotClick

Called when a time slot is clicked in DayView or WeekView:

onTimeSlotClick?: (data: {
  slotStart: DateTimeStringValue;
  slotEnd: DateTimeStringValue;
  nativeEvent: React.MouseEvent<HTMLButtonElement>;
}) => void;
  • slotStart / slotEnd – the slot range in YYYY-MM-DD HH:mm:ss format. Slot length is controlled by the view's intervalMinutes prop.

onAllDaySlotClick

Called when the all-day slot is clicked in DayView or WeekView:

onAllDaySlotClick?: (
  date: DateStringValue,
  event: React.MouseEvent<HTMLButtonElement>
) => void;
  • date – the clicked date in YYYY-MM-DD format.

onDayClick

Called when a day is clicked in MonthView or YearView:

onDayClick?: (
  date: DateStringValue,
  event: React.MouseEvent<HTMLButtonElement>
) => void;
  • date – the clicked date in YYYY-MM-DD format.

onSlotDragEnd

Called when a slot range is selected by dragging across time slots or day cells (requires withDragSlotSelect):

onSlotDragEnd?: (
  rangeStart: DateTimeStringValue,
  rangeEnd: DateTimeStringValue
) => void;
  • rangeStart / rangeEnd – the selected range in YYYY-MM-DD HH:mm:ss format.

onExternalEventDrop

Called when an item is dragged from outside the schedule and dropped onto a slot:

onExternalEventDrop?: (
  dataTransfer: DataTransfer,
  dropDateTime: DateTimeStringValue
) => void;
  • dataTransfer – the native DataTransfer object set by the external item during its onDragStart handler. Read your custom data with dataTransfer.getData(type).
  • dropDateTime – the drop target datetime in YYYY-MM-DD HH:mm:ss format.

Callbacks in resources views

In ResourcesSchedule and Resources* views, onDayClick, onSlotDragEnd and onExternalEventDrop are called with a single object that includes resourceId of the row. onTimeSlotClick payload includes resourceId as well:

onDayClick?: (data: {
  date: DateStringValue;
  nativeEvent: React.MouseEvent<HTMLButtonElement>;
  resourceId?: string | number;
}) => void;

onSlotDragEnd?: (data: {
  rangeStart: DateTimeStringValue;
  rangeEnd: DateTimeStringValue;
  resourceId?: string | number;
}) => void;

onExternalEventDrop?: (data: {
  dataTransfer: DataTransfer;
  dropDateTime: DateTimeStringValue;
  resourceId?: string | number;
}) => void;

canDragEvent / canResizeEvent

Permission callbacks – return false to prevent dragging or resizing for a specific event:

canDragEvent?: (event: ScheduleEventData) => boolean;
canResizeEvent?: (event: ScheduleEventData) => boolean;

preventEventOverlap

Rejects drops and resizes that would make the event overlap another event, see drop validation for what counts as a conflict:

preventEventOverlap?:
  | boolean
  | ((stillEvent: ScheduleEventData, movingEvent: ScheduleEventData) => boolean);

Pass a function to decide per pair of events, return true to forbid the overlap. movingEvent has the new start and end and, in Resources* views, the target resourceId. The function is called many times while dragging and resizing, it must be pure and cheap.

canDropEvent / canResizeEventTo / canDropExternalEvent

Placement callbacks – return false to reject a drop or resize based on where the event is being placed. They are called many times while dragging and again before the placement is committed, so they must be pure and cheap:

canDropEvent?: (data: {
  event: ScheduleEventData;
  start: DateTimeStringValue;
  end: DateTimeStringValue;
  resourceId?: string | number;
}) => boolean;

canResizeEventTo?: (data: {
  event: ScheduleEventData;
  start: DateTimeStringValue;
  end: DateTimeStringValue;
  edge: 'start' | 'end';
}) => boolean;

canDropExternalEvent?: (data: {
  dataTransfer: DataTransfer;
  start: DateTimeStringValue;
  resourceId?: string | number;
}) => boolean;
  • start / end – the candidate range in YYYY-MM-DD HH:mm:ss format. canDropExternalEvent has no end – the schedule does not know the duration of an external item.
  • resourceId – the target resource, only in Resources* views.
  • edge – the edge of the event that is being dragged.
  • dataTransfer – only dataTransfer.types can be read while the drag is in progress.

onEventPlacementRejected

Called when a drop, resize or external drop is rejected by preventEventOverlap or by one of the placement callbacks above. The payload is a discriminated union keyed on action:

onEventPlacementRejected?: (
  data:
    | {
        action: 'drop';
        event: ScheduleEventData;
        start: DateTimeStringValue;
        end: DateTimeStringValue;
        conflicts: ScheduleEventData[];
        reason: 'overlap' | 'rejected';
        resourceId?: string | number;
      }
    | {
        action: 'resize';
        event: ScheduleEventData;
        edge: 'start' | 'end';
        start: DateTimeStringValue;
        end: DateTimeStringValue;
        conflicts: ScheduleEventData[];
        reason: 'overlap' | 'rejected';
        resourceId?: string | number;
      }
    | {
        action: 'external-drop';
        dataTransfer: DataTransfer;
        start: DateTimeStringValue;
        conflicts: [];
        reason: 'rejected';
        resourceId?: string | number;
      }
) => void;
  • conflicts – events the placement collided with, empty when the rejection came from a callback.
  • reason – 'overlap' when preventEventOverlap found a conflict, 'rejected' when a callback returned false.
  • resourceId – only in Resources* views: the target resource for drop and external-drop, the event's own resource for resize.

Date and time value formats

Event data and callback payloads use the following string formats consistently:

  • DateStringValue – YYYY-MM-DD (e.g. 2024-01-15)
  • DateTimeStringValue – YYYY-MM-DD HH:mm:ss (e.g. 2024-01-15 10:00:00)

These types are shared across @mantine/dates and @mantine/schedule and are exported from both packages.