# Event Calendar

> The EventCalendar component — a day/week/month/agenda calendar whose events round-trip across the Dash boundary as plain dicts with ISO-string dates.

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


---



### Overview

`dms.EventCalendar` wraps the **MUI X Event Calendar** (Community, MIT — no
license key required). It renders a day / week / month / agenda calendar that
your users can read and edit: create, drag-to-reschedule, resize and delete
events directly in the UI.

```python
import dash_mui_scheduler as dms
```

The calendar is **interactive on its own**. A standalone `dms.EventCalendar`
with no callback already persists every create / move / resize / delete,
because each edit round-trips through Dash's own `setProps`. You only add a
callback when you want to *observe* the result — to render the current events,
react to the last action, or sync `view` / `visibleDate` elsewhere.


    The MUI X Scheduler is in beta. APIs may shift between releases. The props
    documented here are the ones the Dash wrapper exposes today.

### The data boundary

Everything the calendar shows and everything the user changes crosses the Dash
boundary as **plain, JSON-serializable values** — no Python `datetime` objects,
no functions. Dates are **ISO strings**.

#### Events in, events out

`events` is a list of dicts and is **both an input and an output**. You pass
events in; the calendar writes the *full new array* back to the same prop on
every create, move, resize and delete. Read it from a callback to keep your
own state in sync.

Each event dict has four **required** keys:

| Key     | Type        | Notes                                                        |
| ------- | ----------- | ------------------------------------------------------------ |
| `id`    | str \| int  | Unique within the array.                                     |
| `title` | str         | Shown on the event block.                                    |
| `start` | ISO str     | e.g. `"2024-01-15T09:00:00"`. A trailing `Z` means UTC.      |
| `end`   | ISO str     | Same format as `start`.                                      |

Common **optional** keys: `description`, `resource` (a resource id), `allDay`,
`color` (one of the 11 palette names), `timezone` (IANA name), `draggable`,
`resizable` (`bool | 'start' | 'end'`), `readOnly` and `className`. On
`EventCalendarPremium`, events may also carry `rrule` and `exDates` for
recurrence.


    Always pass dates as strings. `"2024-01-15T10:00:00"` (no `Z`) is *wall
    time*; `"2024-01-15T10:00:00Z"` is a UTC instant. `displayTimezone`
    controls only how events are *rendered* — it never rewrites their data.

#### lastAction (output only)

`lastAction` is a convenience **output** describing the most recent change to
`events`. It is a dict:

```python
{"type": "move", "event": { ... }, "event_timestamp": 1705312800000}
```

`type` tells you what just happened:

| `type`   | When it fires                                            | `event`            |
| -------- | ------------------------------------------------------- | ------------------ |
| `create` | A new event was added in the UI.                        | the new event      |
| `update` | An event's fields were edited (e.g. via the dialog).    | the updated event  |
| `delete` | An event was removed.                                   | the removed event  |
| `move`   | An event was dragged to a new time / day.               | the moved event    |
| `resize` | An event's start or end edge was dragged.               | the resized event  |
| `change` | A bulk / unclassified change to the array.              | `None`             |

`event_timestamp` is an epoch-milliseconds integer — use it as a callback
trigger that changes on every action, even when the same event is touched
twice in a row.

#### Visible date and other controlled props

`visibleDate` is an ISO **date** string (e.g. `"2024-01-15"`) and is
controlled both in and out — it is written back when the user navigates. Its
uncontrolled twin is `defaultVisibleDate`. Several props follow the same
controlled / uncontrolled pattern: `view` / `defaultView`,
`preferences` / `defaultPreferences`, and
`visibleResources` / `defaultVisibleResources`.


    The calendar follows the surrounding Mantine color scheme. Do not write a
    theme callback — toggle your app's color scheme and the calendar follows.

### A controlled calendar

The example below keeps the calendar uncontrolled (it manages its own edits)
and adds a single callback that mirrors the two output sides of the boundary:
the live `events` array and the latest `lastAction`, both rendered as JSON.

Create, drag, resize or delete an event in the calendar and watch both panels
update. The events pinned around **2024-01-15** are visible on load because the
calendar starts at `defaultVisibleDate="2024-01-15"`.



```python
# File: docs/event_calendar/overview.py

"""A controlled EventCalendar: the calendar is fully interactive on its own,
and a callback mirrors the live `events` array and the most recent
`lastAction` back to the page as JSON."""

import json

from dash import html, dcc, Input, Output, callback
import dash_mantine_components as dmc
import dash_mui_scheduler as dms

# Events cross the Dash boundary as plain dicts with ISO-string dates.
# "...:00" with no "Z" is wall time; a trailing "Z" would mean a UTC instant.
events = [
    {
        "id": "kickoff",
        "title": "Project kickoff",
        "start": "2024-01-15T09:00:00",
        "end": "2024-01-15T10:30:00",
        "color": "blue",
        "description": "Align on scope for the quarter.",
    },
    {
        "id": "design-review",
        "title": "Design review",
        "start": "2024-01-16T13:00:00",
        "end": "2024-01-16T14:00:00",
        "color": "purple",
    },
    {
        "id": "team-lunch",
        "title": "Team lunch",
        "start": "2024-01-17T12:00:00",
        "end": "2024-01-17T13:00:00",
        "color": "green",
    },
    {
        "id": "retro",
        "title": "Sprint retro",
        "start": "2024-01-18T16:00:00",
        "end": "2024-01-18T17:00:00",
        "color": "amber",
    },
]

component = dmc.Stack(
    [
        dms.EventCalendar(
            id="event_calendar-overview-cal",
            events=events,
            defaultView="week",
            defaultVisibleDate="2024-01-15",
            eventColor="teal",
            height=600,
        ),
        dmc.Group(
            [
                dmc.Stack(
                    [
                        dmc.Text("Live events array", fw=600, size="sm"),
                        dmc.Code(
                            id="event_calendar-overview-events",
                            block=True,
                            style={"maxHeight": 320, "overflow": "auto"},
                        ),
                    ],
                    gap=4,
                    style={"flex": 1, "minWidth": 280},
                ),
                dmc.Stack(
                    [
                        dmc.Text("Most recent lastAction", fw=600, size="sm"),
                        dmc.Code(
                            id="event_calendar-overview-action",
                            block=True,
                            style={"maxHeight": 320, "overflow": "auto"},
                        ),
                    ],
                    gap=4,
                    style={"flex": 1, "minWidth": 280},
                ),
            ],
            grow=True,
            align="flex-start",
        ),
    ],
    gap="md",
)


@callback(
    Output("event_calendar-overview-events", "children"),
    Output("event_calendar-overview-action", "children"),
    Input("event_calendar-overview-cal", "events"),
    Input("event_calendar-overview-cal", "lastAction"),
)
def show_boundary(current_events, last_action):
    """Render the two OUTPUT sides of the boundary as pretty JSON."""
    events_json = json.dumps(current_events or [], indent=2)
    action_json = json.dumps(last_action or {}, indent=2)
    return events_json, action_json
```


### Props

Full prop reference for `dms.EventCalendar`. Use only these props — do not
invent new ones.


#### `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: /event-calendar*
