Drag & Resize
Toggle and fine-tune drag-and-drop and resizing in the dash-mui-scheduler EventCalendar, including per-event overrides and external drag.
Drag & Resize
The MUI X Scheduler lets users reschedule an event by dragging it to a new time, and change its duration by dragging its edges. dms.EventCalendar exposes both behaviours through props and they are on by default — a calendar with no callbacks at all is already fully interactive. Every move or resize is written back to the events array (input and output) and announced through lastAction, so all you have to do is read those props.
events is both an input and an output. When the user drags or resizes an event, the component sends the entire new array back to Dash. Dates are plain ISO strings (e.g. "2024-01-15T10:00:00"), never Python datetime objects. lastAction is output-only and reports the most recent interaction — its type is one of create, update, delete, move, resize, or change.
Dragging — areEventsDraggable
areEventsDraggable (bool, default True) controls whether events can be picked up and dropped onto a new time or day. Set it to False to pin every event in place while still allowing creation and deletion. Dragging an event emits a lastAction of type move.
Resizing — areEventsResizable
areEventsResizable (default True) controls whether an event's edges can be dragged to change its duration. It accepts:
True— both the start and end edges are resizable.False— the event keeps a fixed duration.'start'— only the leading (start) edge can be dragged.'end'— only the trailing (end) edge can be dragged.
Resizing emits a lastAction of type resize.
Live toggles
The example below wires a dmc.Switch to areEventsDraggable and a dmc.SegmentedControl to areEventsResizable, so you can feel the difference between each mode. A read-out below the calendar shows the latest lastAction, which makes it easy to tell a move apart from a resize.
# File: docs/drag_resize/drag_resize_toggles.py
"""Toggle drag-and-drop and resizing on an EventCalendar at runtime.
A `dmc.Switch` drives `areEventsDraggable` and a `dmc.SegmentedControl` drives
`areEventsResizable` (True / False / 'start' / 'end'). The read-out shows the
latest `lastAction` so you can tell a move apart from a resize.
"""
from dash import html, Input, Output, callback
import dash_mantine_components as dmc
import dash_mui_scheduler as dms
EVENTS = [
{"id": 1, "title": "Team Meeting", "start": "2024-01-15T10:00:00", "end": "2024-01-15T11:00:00", "color": "blue"},
{"id": 2, "title": "Project Review", "start": "2024-01-16T14:00:00", "end": "2024-01-16T15:30:00", "color": "purple"},
{"id": 3, "title": "Client Call", "start": "2024-01-17T09:00:00", "end": "2024-01-17T10:00:00", "color": "green"},
{"id": 4, "title": "Locked: Sprint Demo", "start": "2024-01-18T13:00:00", "end": "2024-01-18T14:00:00",
"color": "grey", "draggable": False, "resizable": False},
]
component = dmc.Stack(
[
dmc.Group(
[
dmc.Switch(
id="drag_resize-draggable-switch",
label="areEventsDraggable",
checked=True,
),
dmc.SegmentedControl(
id="drag_resize-resizable-control",
data=[
{"label": "Both", "value": "true"},
{"label": "Off", "value": "false"},
{"label": "Start edge", "value": "start"},
{"label": "End edge", "value": "end"},
],
value="true",
),
],
align="center",
gap="lg",
),
dms.EventCalendar(
id="drag_resize-cal",
events=EVENTS,
defaultVisibleDate="2024-01-15",
areEventsDraggable=True,
areEventsResizable=True,
height=600,
),
dmc.Code(id="drag_resize-readout", block=True),
],
gap="md",
)
@callback(
Output("drag_resize-cal", "areEventsDraggable"),
Output("drag_resize-cal", "areEventsResizable"),
Input("drag_resize-draggable-switch", "checked"),
Input("drag_resize-resizable-control", "value"),
)
def set_interactions(draggable, resizable):
# Map the SegmentedControl string back to the prop's bool/'start'/'end' shape.
resizable_value = {"true": True, "false": False, "start": "start", "end": "end"}[resizable]
return draggable, resizable_value
@callback(
Output("drag_resize-readout", "children"),
Input("drag_resize-cal", "lastAction"),
)
def show_last_action(last_action):
if not last_action:
return "Drag an event to move it, or drag its edge to resize it — lastAction shows up here."
event = last_action.get("event") or {}
return (
f"lastAction.type: {last_action.get('type')}\n"
f"event: {event.get('title', '-')} "
f"{event.get('start', '-')} -> {event.get('end', '-')}"
)
Per-event and per-resource overrides
The calendar-wide props set the default, but individual events and resources can opt in or out:
- Per event: add
draggable(bool) and/orresizable(bool | 'start' | 'end')
to an event dict. A locked event might use {"draggable": False, "resizable": False} even while the rest of the calendar stays movable. (readOnly: True locks an event completely.)
- Per resource: a resource dict accepts
areEventsDraggable,
areEventsResizable, and areEventsReadOnly, applying that policy to every event assigned to the resource.
These overrides are read straight off the events / resources data — there is no extra prop to enable them.
External drag — drag in and out of the calendar
Two props control whether events can cross the calendar's boundary:
canDragEventsFromTheOutside(bool, defaultFalse) — allow an item from
outside the calendar to be dropped onto it as a new event.
canDropEventsToTheOutside(bool, defaultFalse) — allow an event to be
dragged out of the calendar (for example, to remove it or hand it to another surface).
These enable the cross-boundary drag targets; wiring an actual external drag source (a palette of draggable items elsewhere on the page) is left to your own layout. Both default to False, so the calendar is self-contained until you opt in.
The MUI X Scheduler is in beta. Drag-and-drop and resizing work, but finer external-drag integration may change in future releases.
EventCalendar props
EventCalendar props
| prop | type | description | |||||
|---|---|---|---|---|---|---|---|
id | string; optional | The id used to identify this component in Dash callbacks. | |||||
areEventsDraggable | boolean; optional | Allow drag-to-reschedule. Default True. | |||||
areEventsResizable | boolean \ | a value equal to: 'start', 'end'; optional | Allow resize (bool, or restrict to "start"/"end"). Default True. | ||||
canDragEventsFromTheOutside | boolean; optional | Allow external events to be dragged in. Default False. | |||||
canDropEventsToTheOutside | boolean; optional | Allow events to be dragged out of the calendar. Default False. | |||||
className | string; optional | CSS class applied to the wrapping div. | |||||
defaultPreferences | dict; optional | Uncontrolled initial preferences (same shape as preferences). defaultPreferences is a dict with keys: - ampm (boolean; optional) - weekStartsOn (a value equal to: 0, 1, 2, 3, 4, 5, 6; optional) - showWeekends (boolean; optional) - showWeekNumber (boolean; optional) - isSidePanelOpen (boolean; optional) - showEmptyDaysInAgenda (boolean; optional) | |||||
defaultView | a value equal to: 'day', 'week', 'month', 'agenda'; optional | Uncontrolled initial view. Default "week". | |||||
defaultVisibleDate | string; optional | Uncontrolled initial visible date (ISO string). Default today. | |||||
defaultVisibleResources | dict; optional | Uncontrolled initial resource visibility map. Default {} (all visible). | |||||
displayTimezone | string; optional | Timezone used to render events: an IANA name ("America/New_York"), or "default" / "locale" / "UTC". Render-only — events keep their own data timezone. Default "default". | |||||
eventColor | a value equal to: 'red', 'pink', 'purple', 'indigo', 'blue', 'teal', 'green', 'lime', 'amber', 'orange', 'grey'; optional | The default color palette used for all events. Overridden per resource (eventColor) and per event (color). Default "teal". | |||||
eventCreation | dict; optional | Configures event creation. False disables it; True enables it with defaults; an object sets the interaction and default duration (minutes). eventCreation is a boolean \ | dict with keys: - interaction (a value equal to: 'click', 'double-click'; optional) - duration (number; optional) | ||||
eventDialogTopOffset | number; optional | On desktop, inset the event drawer this many px from the top — e.g. set it to your fixed app header's height so the drawer lines up with a sidebar instead of covering the header. Default 0. | |||||
eventDialogVariant | a value equal to: 'drawer', 'dialog'; default 'drawer' | How the event editor is presented. "drawer" (default) restyles the built-in dialog into a responsive drawer — right-anchored on desktop, an 80%-height bottom sheet on mobile (below mobileBreakpoint), with a scrollable body and pinned header/actions. "dialog" keeps the library's default floating, draggable dialog. | |||||
events | list of dicts; optional | The events to render. Each event is a dict with at least id, title, start and end (ISO strings). This is BOTH an input and an output: the calendar writes the full array back on every create / edit / move / resize / delete. events is a list of dicts with keys: - id (string \ | number; required): Unique id (string or number). - title (string; required): Event title. - start (string; required): Start date-time, ISO string. "Z" suffix = UTC instant. - end (string; required): End date-time, ISO string. "Z" suffix = UTC instant. - description (string; optional): Optional longer description (shown in the event dialog). - timezone (string; optional): IANA timezone the wall-time start/end are interpreted in. - resource (string \ | number; optional): Id of the resource this event belongs to. - rrule (string \ | dict; optional): Recurrence rule — an RFC-5545 RRULE string ("FREQ=WEEKLY;INTERVAL=2;BYDAY=TH") or an object {freq, interval, byDay, byMonthDay, byMonth, count, until}. Recurrence is a Premium feature (use EventCalendarPremium). - exDates (list of strings; optional): Exception dates (ISO strings) excluded from the recurrence. - allDay (boolean; optional): Whether the event spans the whole day. - readOnly (boolean; optional): Whether the event cannot be edited / dragged / resized. - color (a value equal to: 'red', 'pink', 'purple', 'indigo', 'blue', 'teal', 'green', 'lime', 'amber', 'orange', 'grey'; optional): Event color (overrides resource + component color). - draggable (boolean; optional): Per-event drag override. - resizable (boolean \ | a value equal to: 'start', 'end'; optional): Per-event resize override (bool or which edge). - className (string; optional): Custom CSS class for the event element. - extractedFromId (string \ | number; optional): Id of the event this one was split from. |
height | number \ | string; default 600 | Height of the wrapping container (the calendar fills it). Default 600. | ||||
lastAction | dict; optional | Convenience OUTPUT describing the most recent change to events: {type: "create"\ | "update"\ | "delete"\ | "move"\ | "resize"\ | "change", event: the affected event (or None), event_timestamp}. lastAction is a dict with keys: - type (string; optional) - event (dict; optional) - event_timestamp (number; optional) |
localeText | dict; optional | Override UI label strings (a partial map of translation keys). | |||||
mobileBreakpoint | number; default 768 | Width (px) below which the UI switches to its mobile layout. Default 768. | |||||
preferences | dict; optional | Controlled user preferences. Also an OUTPUT. {ampm, weekStartsOn (0=Sun..6=Sat), showWeekends, showWeekNumber, isSidePanelOpen, showEmptyDaysInAgenda}. preferences is a dict with keys: - ampm (boolean; optional) - weekStartsOn (a value equal to: 0, 1, 2, 3, 4, 5, 6; optional) - showWeekends (boolean; optional) - showWeekNumber (boolean; optional) - isSidePanelOpen (boolean; optional) - showEmptyDaysInAgenda (boolean; optional) | |||||
preferencesMenuConfig | dict; optional | Which items appear in the preferences menu, or False to hide the menu. preferencesMenuConfig is a a value equal to: false \ | dict with keys: - toggleWeekendVisibility (boolean; optional) - toggleWeekNumberVisibility (boolean; optional) - toggleAmpm (boolean; optional) - toggleEmptyDaysInAgenda (boolean; optional) - toggleWeekStartsOn (boolean; optional) | ||||
readOnly | boolean; optional | Global read-only mode (disables create / drag / resize / dialog). | |||||
resources | list of dicts; optional | Resources events can be assigned to (supports nested children). | |||||
responsiveSidePanel | boolean; default True | When True (default), the side panel starts open on wide screens and collapsed below mobileBreakpoint on first render — unless you pin isSidePanelOpen via preferences / defaultPreferences. | |||||
scrollToCurrentTime | boolean; default False | In the day / week views, scroll the time grid on first render (and on view change) so the current-time indicator is centered in view. Pairs with showCurrentTimeIndicator. Default False. | |||||
shouldEventRequireResource | boolean; optional | Require every event to be assigned to a resource. Default False. | |||||
showCurrentTimeIndicator | boolean; optional | Show the current-time indicator line in time views. Default True. | |||||
sx | dict; optional | MUI sx styling object applied to the calendar (object form only). | |||||
view | a value equal to: 'day', 'week', 'month', 'agenda'; optional | Controlled active view. Also an OUTPUT (updated on view change). | |||||
views | list of a value equal to: 'day', 'week', 'month', 'agenda's; optional | Which views are offered. Default ["day","week","month","agenda"]. | |||||
visibleDate | string; optional | Controlled visible date (ISO string). Drives which date range is shown. Also an OUTPUT — written back (ISO string) when the user navigates. | |||||
visibleResources | dict; optional | Controlled resource visibility map {resourceId: bool}. Also an OUTPUT. |
Source: /drag-resize
Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs:
- /drag-resize/llms.txt — LLM-friendly documentation
- /sitemap.xml
- /robots.txt