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

> **Full documentation:** [https://muischeduler.2plot.dev](https://muischeduler.2plot.dev) — the dedicated dash-mui-scheduler documentation site, with the complete API reference and deeper examples. This page is the quick-start overview.



### Installation

[Visit GitHub Repo](https://github.com/pip-install-python/dash-mui-scheduler) · [PyPI](https://pypi.org/project/dash-mui-scheduler/)

```bash
pip install dash-mui-scheduler
```

### Introduction

`dash-mui-scheduler` is the successor to `dash-fullcalendar` — it replaces it in this catalogue. It wraps the [MUI X Scheduler](https://mui.com/x/react-scheduler/) for Plotly Dash, so you can build event calendars and resource timelines in pure Python.

Events cross the Dash ↔ Python boundary as plain dictionaries with ISO-string dates, and every user interaction (create / move / resize / delete) round-trips straight back into your callbacks. Dark mode is automatic — the components follow the surrounding Dash Mantine Components color scheme.

The suite includes:

| Component | Plan | What it is |
|:----------|:-----|:-----------|
| `EventCalendar` | **Community (MIT)** | Day / week / month / agenda calendar with drag-and-drop, resizing, resources, and an editing dialog. No license key. |
| `EventCalendarPremium` | Premium | The calendar plus the recurrence engine (RRULE events + exception dates). |
| `EventTimeline` | Premium | A resource-row, Gantt-style timeline across configurable zoom presets. |
| `RadialLineChart` | Premium (preview) | Polar line/area charts for trends along periodic values. |
| `RadialBarChart` | Premium (preview) | Polar bar charts for comparing values along periodic categories. |

> The underlying MUI X Scheduler is in **beta** (`@mui/x-scheduler@9.0.0-beta.0`); this wrapper pins the beta exactly, so the upstream API may change before its stable release.

### Quick Start

Pass a list of event dicts — each needs at least `id`, `title`, `start`, and `end` (ISO strings). Optional keys include `description`, `color`, `allDay`, `resource`, and per-event `draggable` / `resizable` / `readOnly` overrides.



```python
# File: docs/dash_mui_scheduler/quickstart_example.py

"""Quick-start EventCalendar example with sample events."""
from datetime import datetime, timedelta

import dash_mantine_components as dmc
import dash_mui_scheduler as dms

# Anchor the sample events to the current week so the calendar
# always opens with something to look at.
_monday = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
_monday -= timedelta(days=_monday.weekday())


def _iso(day_offset: int, hour: int, minute: int = 0) -> str:
    return (_monday + timedelta(days=day_offset, hours=hour, minutes=minute)).isoformat()


# Events are plain dicts with ISO-string dates.
# Required keys: id, title, start, end. Everything else is optional.
events = [
    {
        "id": "1",
        "title": "Team Standup",
        "start": _iso(0, 9),
        "end": _iso(0, 9, 30),
        "color": "blue",
    },
    {
        "id": "2",
        "title": "Design Review",
        "start": _iso(1, 13),
        "end": _iso(1, 14, 30),
        "color": "purple",
        "description": "Review the new dashboard mockups.",
    },
    {
        "id": "3",
        "title": "Client Call",
        "start": _iso(2, 10),
        "end": _iso(2, 11),
        "color": "teal",
    },
    {
        "id": "4",
        "title": "Sprint Demo",
        "start": _iso(3, 15),
        "end": _iso(3, 16),
        "color": "green",
    },
    {
        "id": "5",
        "title": "Conference Day",
        "start": _iso(4, 0),
        "end": _iso(4, 23, 59),
        "allDay": True,
        "color": "orange",
    },
]

component = dmc.Paper(
    dms.EventCalendar(
        id="mui-scheduler-quickstart-cal",
        events=events,
        defaultView="week",
        height=620,
    ),
    withBorder=True,
    p="md",
)
```


### Events & Callbacks

The `events` prop is **both an input and an output**. Seed it with your data; the calendar writes the full new array back whenever the user creates, moves, resizes, or deletes an event. For a lighter-weight signal, `lastAction` reports just the most recent change:

```python
{"type": "create" | "update" | "delete" | "move" | "resize" | "change",
 "event": {...},            # the affected event (or None)
 "event_timestamp": ...}
```

Other stateful props (`view`, `visibleDate`, `preferences`, `visibleResources`) each come as a controlled prop plus an uncontrolled `defaultX` variant, and are written back on change — so you can read the active view or the date the user navigated to in a callback.



```python
# File: docs/dash_mui_scheduler/interactive_example.py

"""Interactive example: round-tripping event edits through callbacks.

`events` is BOTH an input and an output — the calendar writes the full
array back on every create / move / resize / delete. `lastAction` is a
convenience output describing just the most recent change.
"""
import json
from datetime import datetime, timedelta

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

_monday = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
_monday -= timedelta(days=_monday.weekday())


def _iso(day_offset: int, hour: int, minute: int = 0) -> str:
    return (_monday + timedelta(days=day_offset, hours=hour, minutes=minute)).isoformat()


events = [
    {"id": "a", "title": "Drag me around", "start": _iso(0, 10), "end": _iso(0, 11), "color": "indigo"},
    {"id": "b", "title": "Resize my edges", "start": _iso(2, 13), "end": _iso(2, 15), "color": "pink"},
    {"id": "c", "title": "Click to edit or delete", "start": _iso(4, 9), "end": _iso(4, 10), "color": "amber"},
]

component = dmc.Stack(
    [
        dms.EventCalendar(
            id="mui-scheduler-interactive-cal",
            events=events,
            defaultView="week",
            height=560,
            eventCreation={"interaction": "click", "duration": 60},
        ),
        dmc.Group(
            [
                dmc.Badge("try it", color="teal", variant="light"),
                dmc.Text(
                    "Drag, resize, create (click an empty slot), edit, or delete an event — "
                    "every change lands in a Dash callback.",
                    size="sm",
                    c="dimmed",
                ),
            ],
            gap="xs",
        ),
        dmc.SimpleGrid(
            cols={"base": 1, "md": 2},
            children=[
                dmc.Paper(
                    [
                        dmc.Text("lastAction", fw=600, size="sm", mb="xs"),
                        dmc.Code(
                            "Interact with the calendar…",
                            id="mui-scheduler-last-action-output",
                            block=True,
                        ),
                    ],
                    withBorder=True,
                    p="md",
                ),
                dmc.Paper(
                    [
                        dmc.Text("events (round-tripped)", fw=600, size="sm", mb="xs"),
                        dmc.Text(
                            f"{len(events)} events",
                            id="mui-scheduler-event-count-output",
                            size="sm",
                            c="dimmed",
                        ),
                    ],
                    withBorder=True,
                    p="md",
                ),
            ],
        ),
    ],
    gap="md",
)


@callback(
    Output("mui-scheduler-last-action-output", "children"),
    Input("mui-scheduler-interactive-cal", "lastAction"),
    prevent_initial_call=True,
)
def show_last_action(last_action):
    if not last_action:
        return "Interact with the calendar…"
    # lastAction = {"type": "create"|"update"|"delete"|"move"|"resize"|"change",
    #               "event": {...}, "event_timestamp": ...}
    return json.dumps(
        {"type": last_action.get("type"), "event": last_action.get("event")},
        indent=2,
        default=str,
    )


@callback(
    Output("mui-scheduler-event-count-output", "children"),
    Input("mui-scheduler-interactive-cal", "events"),
    prevent_initial_call=True,
)
def show_event_count(current_events):
    current_events = current_events or []
    titles = ", ".join(e.get("title", "?") for e in current_events)
    return f"{len(current_events)} events — {titles}"
```


### Premium Components

`EventCalendarPremium`, `EventTimeline`, and the radial charts wrap MUI X **Premium** packages. They all accept a `licenseKey` prop; without a valid MUI X Premium license key they still render, but with a watermark. All Premium components share the same `@mui/x-license` singleton, so a single key covers everything. The Dash wrapper code in this package is MIT-licensed; the underlying MUI X Premium libraries are not.

#### EventCalendarPremium — recurrence

Same API as `EventCalendar`, plus `licenseKey` and support for recurring events via `rrule` (an RFC-5545 RRULE string or an object) and `exDates` (exception dates):

```python
import os
import dash_mui_scheduler as dms

dms.EventCalendarPremium(
    id="mui-scheduler-premium-cal",
    licenseKey=os.environ["MUI_X_LICENSE_KEY"],
    events=[{
        "id": 1, "title": "Standup",
        "start": "2026-07-06T09:00:00", "end": "2026-07-06T09:15:00",
        "rrule": "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
    }],
    defaultVisibleDate="2026-07-06",
)
```

#### EventTimeline

A Gantt-style timeline that lays events out in resource rows across configurable zoom presets. It shares the calendar's event/resource model (`events`, `resources`, `lastAction`, drag/resize props) and swaps the `view`/`views` props for `preset` / `defaultPreset` / `presets`, plus a `resourceColumnLabel` for the resource column header.

#### Radial Charts (Premium preview)

`RadialLineChart` and `RadialBarChart` are polar charts from `@mui/x-charts-premium`. Pass row-oriented `dataset` rows plus `series` that reference columns via `dataKey`; `rotationAxis` replaces the cartesian x-axis and `radiusAxis` replaces the y-axis. Clicking the chart reports the hit axis item via the `clickData` output. They are `Unstable_` previews — production-ready, but their API may shift.



```python
# File: docs/dash_mui_scheduler/radial_chart_example.py

"""RadialLineChart example (Premium preview).

Renders with a watermark unless a MUI X Premium `licenseKey` is provided.
Set the MUI_X_LICENSE_KEY environment variable to remove it.
"""
import os

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

# Row-oriented data; each series references a column via `dataKey`.
dataset = [
    {"month": "Jan", "london": 49, "paris": 51},
    {"month": "Feb", "london": 38, "paris": 41},
    {"month": "Mar", "london": 40, "paris": 47},
    {"month": "Apr", "london": 44, "paris": 52},
    {"month": "May", "london": 49, "paris": 63},
    {"month": "Jun", "london": 45, "paris": 49},
    {"month": "Jul", "london": 45, "paris": 62},
    {"month": "Aug", "london": 50, "paris": 53},
    {"month": "Sep", "london": 49, "paris": 47},
    {"month": "Oct", "london": 69, "paris": 61},
    {"month": "Nov", "london": 59, "paris": 55},
    {"month": "Dec", "london": 56, "paris": 58},
]

component = dmc.Paper(
    dmc.Stack(
        [
            dms.RadialLineChart(
                id="mui-scheduler-radial-lines",
                height=420,
                licenseKey=os.environ.get("MUI_X_LICENSE_KEY", ""),
                dataset=dataset,
                # rotationAxis = angular (x-like) axis, radiusAxis = radial (y-like) axis
                series=[
                    {"dataKey": "london", "label": "London (mm)", "curve": "natural", "showMark": True},
                    {"dataKey": "paris", "label": "Paris (mm)", "curve": "natural", "showMark": True},
                ],
                rotationAxis=[{"scaleType": "point", "dataKey": "month", "disableLine": True}],
                radiusAxis=[{"disableLine": True}],
                grid={"rotation": True, "radius": True},
            ),
            dmc.Text(
                "Click the chart to inspect an axis item.",
                id="mui-scheduler-radial-click-output",
                size="sm",
                c="dimmed",
                ta="center",
            ),
        ],
        gap="xs",
    ),
    withBorder=True,
    p="md",
)


@callback(
    Output("mui-scheduler-radial-click-output", "children"),
    Input("mui-scheduler-radial-lines", "clickData"),
    prevent_initial_call=True,
)
def show_click(click_data):
    if not click_data:
        return "Click the chart to inspect an axis item."
    return (
        f"Clicked {click_data.get('axisValue')} — "
        f"series values: {click_data.get('seriesValues')}"
    )
```


### EventCalendar Properties

| Property | Type | Default | Description |
|:---------|:-----|:--------|:------------|
| `id` | string | - | Component ID for Dash callbacks. |
| `events` | list of dicts | - | The events to render. Each needs `id`, `title`, `start`, `end` (ISO strings); optional `description`, `timezone`, `resource`, `rrule`, `exDates`, `allDay`, `readOnly`, `color`, `draggable`, `resizable`, `className`. **Input AND output** — written back on every edit. |
| `lastAction` | dict | - | **Output.** The most recent change: `{type, event, event_timestamp}`. |
| `view` | `'day'` \| `'week'` \| `'month'` \| `'agenda'` | - | Controlled active view. Also an **output** (updated on view change). |
| `defaultView` | string | `'week'` | Uncontrolled initial view. |
| `views` | list of strings | `['day','week','month','agenda']` | Which views are offered. |
| `visibleDate` | string | - | Controlled visible date (ISO string). Also an **output** on navigation. |
| `defaultVisibleDate` | string | today | Uncontrolled initial visible date. |
| `eventColor` | string | `'teal'` | Default event palette: `red`, `pink`, `purple`, `indigo`, `blue`, `teal`, `green`, `lime`, `amber`, `orange`, `grey`. Overridden per resource and per event. |
| `eventCreation` | bool \| dict | - | `False` disables creation; a dict sets `{interaction: 'click'\|'double-click', duration}` (minutes). |
| `resources` | list of dicts | - | Resources events can be assigned to (supports nested `children`). |
| `visibleResources` | dict | - | Controlled resource visibility map `{resourceId: bool}`. Also an **output**. |
| `defaultVisibleResources` | dict | `{}` | Uncontrolled initial resource visibility (all visible). |
| `shouldEventRequireResource` | boolean | `False` | Require every event to be assigned to a resource. |
| `areEventsDraggable` | boolean | `True` | Allow drag-to-reschedule. |
| `areEventsResizable` | bool \| `'start'` \| `'end'` | `True` | Allow resize (or restrict to one edge). |
| `canDragEventsFromTheOutside` | boolean | `False` | Allow external events to be dragged in. |
| `canDropEventsToTheOutside` | boolean | `False` | Allow events to be dragged out of the calendar. |
| `readOnly` | boolean | - | Global read-only mode (disables create / drag / resize / dialog). |
| `showCurrentTimeIndicator` | boolean | `True` | Show the current-time indicator line in time views. |
| `scrollToCurrentTime` | boolean | `False` | Scroll day/week views so the current time is centered on first render. |
| `displayTimezone` | string | `'default'` | Render timezone: IANA name, `'default'`, `'locale'`, or `'UTC'`. Render-only. |
| `preferences` | dict | - | Controlled user preferences `{ampm, weekStartsOn, showWeekends, showWeekNumber, isSidePanelOpen, showEmptyDaysInAgenda}`. Also an **output**. |
| `defaultPreferences` | dict | - | Uncontrolled initial preferences (same shape). |
| `preferencesMenuConfig` | `False` \| dict | - | Which items appear in the preferences menu, or `False` to hide it. |
| `localeText` | dict | - | Override UI label strings (partial map of translation keys). |
| `eventDialogVariant` | `'drawer'` \| `'dialog'` | `'drawer'` | Event editor presentation: responsive drawer or floating dialog. |
| `eventDialogTopOffset` | number | `0` | Desktop drawer inset from the top (px) — e.g. your fixed header height. |
| `responsiveSidePanel` | boolean | `True` | Side panel opens on wide screens, collapses below `mobileBreakpoint`. |
| `mobileBreakpoint` | number | `768` | Width (px) below which the UI switches to its mobile layout. |
| `height` | number \| string | `600` | Height of the wrapping container. |
| `className` | string | - | CSS class applied to the wrapping div. |
| `sx` | dict | - | MUI `sx` styling object (object form only). |

**Note:** `EventCalendarPremium` accepts all of the above plus `licenseKey`. `EventTimeline` accepts `licenseKey`, `preset` / `defaultPreset` / `presets`, and `resourceColumnLabel` in place of the `view` props; the radial charts take `dataset`, `series`, `rotationAxis`, `radiusAxis`, `grid`, `axisHighlight`, `colors`, `hideLegend`, `margin`, `showToolbar`, `slotProps`, and the `clickData` output. See the component docstrings for full details.
