Move and resize
PassonDragEvent 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).
DOM held presses
On the DOM time grid, touch and pen wait for a 300 ms hold within 8 px before dragging. A tap callsonPressEvent from the event’s own click. A vertical swipe
that starts on an event or resize grip scrolls the grid. During a held drag,
scrolling stops until release or cancellation. Mouse dragging starts immediately.
Set touchDragDelay (milliseconds) and touchDragThreshold (pixels) on DOM
Calendar or TimeGrid to adjust the hold. Movement, pointer cancellation,
another finger, navigation, or unmount cancels a pending hold.
An additional contact on an event or resize grip cannot start a replacement hold
or take over an active drag.
These options apply to event gestures, not empty-slot or month interactions.
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 onedragStepMinutes 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. SetshowDragHandle={false} to hide that indicator while keeping drag-to-move and
drag-to-resize fully working, so events stay editable without the visual marker.
You can toggle showDragHandle after mounting; native time-grid grips update
without replacing the events array.
Colour an event’s grips
SetdragHandleColor on an event to override its resize grip colour in
@super-calendar/native. This applies to both time-grid grips and to the
resource timeline’s grip in either orientation. Omit it to use
theme.colors.eventText. Choose a colour that contrasts with the event’s background.
showDragHandle={false} still hides the time-grid grips. The DOM renderer’s
resize targets have no visible grips, so this field does not change their appearance.
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.
disabled: true, which
also dims it.)
Allow only move or only resize
Split the two withstartEditable (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
Returnfalse 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.
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 needonChangeDate 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.
On native, the floating copy’s horizontal centre selects the destination day.
Its top edge selects the time. This also applies to narrower boxes for overlapping
events, so a copy mostly over a day lands in that column even if its left edge
crosses the previous column.
In-view move, cross-day within the visible columns, and resize all work by gesture
as usual on both.
On the DOM time grid, only mouse drags trigger edge paging. Touch and pen drags
remain inside the visible period. A resting finger cannot repeatedly change the
date or detach its captured event through an edge page.
Rescheduling without dragging
Dragging is a gesture, so every renderer offers the same moves and resizes another way. They run through the same commit path as a drag, soonDragEvent
fires exactly as it would from a gesture (and can still return false to
reject). eventOverlap={false}, draggable: false, startEditable, and
durationEditable apply as they do to a drag.
On React DOM and Solid, choose Edit events, then an event, to open a dialog with Move 15 minutes later /
earlier, Extend / Shorten by 15 minutes, and Move to next / previous
week (per mode: the page span), stepping by dragStepMinutes. It works with a
keyboard, a click, or a tap, and never presses or drags the event itself.
Rejected edits show a polite status message, customizable with
labels.eventChangeRejected. Pass getEventId to retain the dialog’s event
through full data refreshes. See
Move and resize actions.
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. 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
PassonCreateEvent 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.”minHour
and maxHour), the preview stops at that edge. Its border and minimum height stay
inside the column, including borders from a createGhost class or style. The
preview does not change onCreateEvent, which still receives the snapped range
within the pressed day.
Show a draft in the preview
The preview is empty by default. To show a draft title or the live time range inside it, pass arenderCreateGhost component. It receives start and end
as Dates: the snapped range onCreateEvent would receive if the sweep ended
at the pointer’s current position. They are ordered, at least one
dragStepMinutes step long, and clamped to the pressed day, exactly as on
release. The component re-renders whenever the range changes, before
onCreateEvent fires.
Text (and views) instead of DOM elements:
createGhost slot), and you own only its content. That content is clipped to
the preview box, ignores the pointer, and stays out of the tab order and the
accessibility tree, like the empty preview. Keep it visual: controls inside it
can’t be reached.
A few rules apply:
renderCreateGhostneedsonCreateEvent. On its own it does not enable creation, and with onlyonPressCellthe preview stays empty. RemovingonCreateEventcancels an active sweep.- In React, define the component once outside render, as with
renderEvent. A new inline function on every render remounts the content and drops its state. Calendarforwards it in the time-grid modes (day,3days,week,custom). Month and year sweeps don’t use it.ResourceTimelineaccepts the same prop and adds the lane’sresourceto the props, in both orientations.- The range can extend past a narrowed
minHour/maxHourwindow. On the web the preview box stops at the visible edge, butstartandendkeep matching whatonCreateEventwill receive, which is clamped to the pressed day, not to the visible hours. - In React DOM and Solid, scrolling or zooming during a held sweep updates the preview range even if the pointer does not move again before release.
- The content clears when the sweep ends or is cancelled, and each new sweep
mounts it fresh. Changing the pressed column to another day cancels the sweep.
In React DOM and Solid, Escape or losing pointer capture cancels the sweep,
and a press without a drag shows the one-step range while held, then fires
onPressCellinstead of creating. On React Native, a stationary hold creates that one-step range. A cancelled native gesture clears the preview without callingonCreateEvent. - On React Native, the preview geometry stays on the UI thread. Pointer and zoom updates cross to JavaScript only when the snapped range changes.
On the month grid
The same two handlers work inmonth 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.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’srangeBackground 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.
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.