# Drag & Resize

> Toggle and fine-tune drag-and-drop and resizing in the dash-mui-scheduler EventCalendar, including per-event overrides and external drag.

**Site index:** [https://muischeduler.2plot.dev/llms.txt](https://muischeduler.2plot.dev/llms.txt) — every page on this site, as Markdown.  
**Network index:** [https://2plot.dev/llms.txt](https://2plot.dev/llms.txt) — The 2plot network; start here to discover sibling sites.  
**Sibling sites:** 13 more in The 2plot network — listed in the site index above.  
**Sitemap:** https://muischeduler.2plot.dev/sitemap.xml  


---



### 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**.



```python
# 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/or `resizable` (`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, default `False`) — allow an item from
  outside the calendar to be dropped onto it as a new event.
- `canDropEventsToTheOutside` (bool, default `False`) — 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*
