Full documentation: 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
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 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.
# 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:
{"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.
# 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):
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.
# 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.