Skip to main content
Everything here is opt-in: pass the relevant handler and update your own event state in response. Move, resize, and create work on the week/day grid; move and create also work on the month grid (see On the month grid), where a drag moves an event by whole days rather than by time. The year grid sweeps out day ranges too (see On the year grid).

Move and resize

Pass onDragEvent to make events draggable. Move an event (long-press it on native, click-drag it on web), or drag the grip at its bottom edge to change the end or its top edge to change the start. Drag vertically to change the time, horizontally to move it to another day (within the visible range). New start/end are snapped to dragStepMinutes (default 15).

Move an event past midnight

A move keeps its duration, so dragging an event down past the end of the day lets its end run into the next one: the box cuts off at the day boundary and the remainder previews at the top of the next column, exactly where the committed event will render. The start stays in the day you dropped it on (it stops one dragStepMinutes step before the end of the day), so a move to a different day is still the horizontal drag. onDragEvent then receives a start and end on different dates. Dragging any day’s segment of the resulting multi-day event moves the whole thing, so it never gets clipped to the day you grabbed. All visible segments preview the move together, including segments that enter a new column. Both dates shift together to preserve the event’s duration. For example, moving a Tuesday 17:00 to Thursday 21:00 event one day earlier previews Monday 17:00 to Wednesday 21:00, whichever segment you grab. Use a resize grip to change just the start or end.

Hide the drag handle

By default a small grip shows at each draggable event’s bottom edge. Set showDragHandle={false} to hide that indicator while keeping drag-to-move and drag-to-resize fully working, so events stay editable without the visual marker.

Lock specific events

onDragEvent makes every event draggable, which is the right default: most calendars let you reschedule anything. When a few events must never move (a confirmed booking, an event someone else owns, a holiday), set draggable: false on those events. They keep their normal appearance and still respond to taps, they just can’t be picked up or resized. Nothing else needs to change.
Reach for this when an event can never move, so you don’t offer a drag that only snaps back. To refuse a move for some targets but not others (see below), keep the event draggable and reject the specific drop instead. (For an event that shouldn’t respond to taps either and should read as unavailable, use disabled: true, which also dims it.)

Allow only move or only resize

Split the two with startEditable (can be moved) and durationEditable (can be resized), per event or grid-wide via eventStartEditable / eventDurationEditable (both default true). A draggable: false event stays fully locked regardless.

Reject a drop

Return false from onDragEvent to refuse a particular placement — the event snaps back to where it started (on the time grid a cross-week drop snaps the view back too, so the rejection is visible). Use it for rules that depend on where the event lands: overlaps, out-of-bounds slots, or business-hours limits. The library is expo-free, so fire your own feedback (a haptic, a toast) right where you reject.
The overlap case is common enough that it’s built in: set eventOverlap={false} and the grid rejects any drag or resize that would land an event on top of another, without you checking in onDragEvent. For your own rules, eventsOverlap and overlapsOtherEvents are exported from @super-calendar/core.

Haptics on grab

onDragStart fires the instant an event is picked up for a move or resize, before anything is committed. The library is expo-free, so bring your own haptics:

Move an event to another week

While moving an event, drag it past the left or right edge of the day columns and hold briefly. The view pages to the previous/next period and the event lifts into a floating copy that keeps following your finger, so the drag stays live across the page change and you drop it on any day of the newly revealed week. Both renderers need onChangeDate set (they already do for paging); the page only advances on a deliberate dwell at the very edge, so a normal in-view drag never trips it. On native the pager’s own swipe is frozen for the moment it pages, so the view advances under your held finger instead of waiting for you to lift. In-view move, cross-day within the visible columns, and resize all work by gesture as usual on both.

Screen-reader rescheduling

Dragging is a gesture, so on the React Native renderer draggable events also carry accessibility actions for VoiceOver / TalkBack users: move earlier, move later, (when the event owns its end) extend / shorten, and move to next / previous week (per-mode: the page span), each stepping by dragStepMinutes or a whole page. They run through the same commit path as a drag, so onDragEvent fires exactly as it would from a gesture (and can still return false to reject). The built-in event renderer wires these up automatically; a custom renderEvent should spread the accessibilityActions and onAccessibilityAction it receives onto its pressable to keep the event operable by assistive tech.

Drag to create

Pass onCreateEvent to sweep out a new event on empty grid space: long-press and drag on native, click-drag on web. The handler receives the snapped start/end on release (a stationary press yields a one-step range). On native it supersedes onLongPressCell; on web, dragging empty space creates instead of scrolling (use the wheel to scroll), and Escape cancels an in-progress sweep before it commits.
A live ghost box previews the range as you sweep. Tap (no drag) on empty space still fires onPressCell with the pressed date+time, so you can support both “tap to create a point” and “drag to create a range.”

On the month grid

The same two handlers work in month mode on both renderers. Nothing extra to enable: pass onCreateEvent, onDragEvent, or both.

Drag to create a day span

Press an empty day and drag across others to sketch an all-day span, then release. start is midnight of the first day and end is midnight after the last (exclusive). On native you long-press first, so a tap and a page swipe are never hijacked, and a stationary hold creates that single day; on web a plain click without dragging creates nothing and still fires onPressDay.
onSelectDrag reports the same sweep as it happens, with the ordered inclusive [start, end] days, so a selection highlight can follow the drag rather than appearing only on release. Set it, onCreateEvent, or both; either enables the gesture. See Date selection for wiring it to useDateRange.

Drag to reschedule

Pick an event bar up and drop it on another day. Both ends shift by the same number of calendar days, so the time of day and the duration are preserved (a multi-day event keeps its length). Grab it with a long-press on native and a press-drag on web. The carried bar fades and the target day is tinted while you drag.
Everything above applies here too: draggable: false and startEditable: false lock an event, eventStartEditable={false} locks the whole grid, returning false rejects a drop, and eventOverlap={false} rejects one that would land on top of another event. onDragStart fires on grab, for haptics. There is no resize on the month grid, so durationEditable has no effect there.

Styling the drag states

Both states are tinted with the theme’s rangeBackground token by default (see Theming), and the bar being carried fades. On the dom renderer each day in a create sweep also carries data-creating and the day an event is about to land on carries data-drop, so you can restyle either (see Styling); give the day slot a class to take the tint over entirely.

On the year grid

The twelve mini months take the same sweep: onSelectDrag reports the ordered inclusive [start, end] days as you drag, and onCreateEvent reports the all-day range once on release. Hold a day and drag on a device, press and drag on the web. Days being swept carry data-creating on the dom renderer.
On a device a sweep stays inside the mini month it started in; on the web it can carry on across months. The year view summarises events as dots rather than bars, so it has nothing to pick up: onDragEvent applies to month mode, not year.

Tuning the snap

dragStepMinutes (default 15) controls how move, resize, and create snap on the week/day grid. The month and year grids always snap to whole days.