<- Back to Complex Components

Purpose

Calendar renders an event calendar with month, week, and day views. It displays dated events, highlights selected days or time slots, can expose custom selection buttons, emits calendar interaction intents through its primary action, and can emit an event-click action with the clicked event payload.

Use it for schedule, agenda, booking, and planning surfaces where events are supplied by the module. The component does not fetch events by itself and does not persist user selections automatically; actions must return store, data model, or property updates when the selection or event list must be synchronized.

Constructor

Calendar(
    id: str,
    value: str = "",
    min_date: str = "",
    max_date: str = "",
    max_width: int | None = None,
    action: str | ActionSpec | None = None,
    params: dict | None = None,
    *,
    label: str = "",
    date_format: str = "yyyy-MM-dd",
    input_mask: str = "",
    show_input: bool = True,
    events: list | None = None,
    view: str = "month",
    current_date: str = "",
    selected_dates: list | None = None,
    selected_slots: list | None = None,
    buttons: list | None = None,
    on_event_click: str | ActionSpec | None = None,
    on_event_click_params: dict | None = None,
    time_from: int = 0,
    time_to: int = 24,
)

Properties

Python argument Payload/YAML property Type Default Description
label label str "" Optional field label. The desktop renderer displays it in the field shell.
value value str "" Legacy selected-date value. The desktop event calendar can use it as the initial date when current_date is empty.
min_date min_date str "" Serialized legacy date-picker bound. It is not enforced by the current event-calendar renderers.
max_date max_date str "" Serialized legacy date-picker bound. It is not enforced by the current event-calendar renderers.
max_width max_width int \| null null Optional field-shell width limit where supported by the renderer shell.
date_format date_format str "yyyy-MM-dd" Serialized legacy date-picker format. Event dates should still be supplied as ISO yyyy-MM-dd.
input_mask input_mask str "" Serialized legacy date-picker mask. It is not used by the event-calendar grid.
show_input show_input bool true Serialized legacy date-picker flag. It is not used by the event-calendar grid.
events events list[dict] [] Events rendered in the month, week, and day views.
view view str "month" Initial view. Supported values are "month", "week", and "day". Unknown values fall back to month in the desktop renderer.
current_date current_date str "" ISO date used as the visible month, week, or day anchor.
selected_dates selected_dates list[str] [] Selected ISO dates for month view. The UI treats month selection as single-day selection.
selected_slots selected_slots list [] Selected time slots. Week view uses objects with date and time; day view uses HH:MM strings.
buttons buttons list[dict] [] Custom buttons displayed in the selection bar when there is a selected day or slot.
action action action spec null Primary interaction action for navigation, view changes, day clicks, slot clicks, and desktop create-event requests.
params action.context dict {} Context merged into the primary action payload.
on_event_click on_event_click action spec null Action emitted when an event item is clicked.
on_event_click_params on_event_click.context dict {} Context merged into the event-click action payload.
time_from time_from int 0 First hour shown in week/day time grids, clamped to 0.
time_to time_to int 24 End hour for week/day time grids, clamped to 24.

For direct property updates and YAML definitions, use the payload property names.

Action Confirmation

Use confirm inside the ActionSpec for the primary action, on_event_click, or any custom buttons[].action. Confirmation text should use translation keys.

Primary calendar interactions confirm before changing local calendar state. If the user cancels a primary action confirmation, the view, visible date, selected day, or selected slot remains unchanged.

calendar = sdk.ui.Calendar(
    "calendar_confirm",
    events=[
        {
            "_id": "event_alpha",
            "date": "2026-04-29",
            "time": "09:00",
            "title": "Confirmable event",
        }
    ],
    view="month",
    current_date="2026-04-29",
    action={
        "name": "components.calendar_confirm_action",
        "context": {"source": "python_calendar_primary"},
        "confirm": {
            "text": sdk.i18n.t("components.calendar.confirm.primary_prompt"),
            "confirm_text": sdk.i18n.t("components.calendar.confirm.accept"),
            "cancel_text": sdk.i18n.t("components.calendar.confirm.cancel"),
        },
    },
    on_event_click={
        "name": "components.calendar_confirm_action",
        "context": {"source": "python_calendar_event"},
        "confirm": {
            "text": sdk.i18n.t("components.calendar.confirm.event_prompt"),
            "confirm_text": sdk.i18n.t("components.calendar.confirm.accept"),
            "cancel_text": sdk.i18n.t("components.calendar.confirm.cancel"),
        },
    },
    buttons=[
        {
            "label": sdk.i18n.t("components.calendar.confirm.button_label"),
            "variant": "primary",
            "action": {
                "name": "components.calendar_confirm_action",
                "context": {"source": "python_calendar_button"},
                "confirm": {
                    "text": sdk.i18n.t("components.calendar.confirm.button_prompt"),
                    "confirm_text": sdk.i18n.t("components.calendar.confirm.accept"),
                    "cancel_text": sdk.i18n.t("components.calendar.confirm.cancel"),
                },
            },
        }
    ],
)

Event Shape

Field Type Description
_id str Optional stable id used by module actions. The renderer does not require it.
date str ISO date (yyyy-MM-dd). Used to place the event on the calendar.
start str Optional ISO datetime fallback used by renderers when date is missing.
time str Time label such as 09:00. Week view groups by hour; day view places events into 30-minute buckets.
title str Display text for the event.
duration int Duration in minutes. Day view uses it to span event blocks.
description str Optional detail shown in day view and available to event-click actions.
color str Optional CSS/Qt color used for the event marker or block.

Selection Shapes

View Property Shape
Month selected_dates ["2026-03-18"]
Week selected_slots [{"date": "2026-03-23", "time": "09:00"}]
Day selected_slots ["09:30", "10:00"]

Week selection is same-day multi-select in the renderers. Selecting a slot on another day clears the previous week selection.

Mutable Capabilities

Calendar exposes these mutable capabilities by default:

Property Capabilities
value value.set, value.append
events events.set, events.append, events.remove, events.replace
selected_dates selected_dates.set, selected_dates.append, selected_dates.remove
selected_slots selected_slots.set, selected_slots.append, selected_slots.remove
visibility state visible.set, enabled.set

Direct updates to other rendered properties, such as label, view, current_date, buttons, time_from, or time_to, must be declared explicitly with allow(...) or YAML capabilities.

Calendar Example

from democrai.sdk.client import active_sdk as sdk
from democrai.sdk.ui import bound

events = [
    {
        "_id": "cal_evt_standup",
        "date": "2026-03-05",
        "time": "09:00",
        "title": "Team standup",
        "duration": 30,
        "description": "Daily project sync.",
        "color": "#2563eb",
    },
    {
        "_id": "cal_evt_review",
        "date": "2026-03-18",
        "time": "11:00",
        "title": "Board review",
        "duration": 120,
        "description": "Quarterly planning session.",
        "color": "#7c3aed",
    },
]

buttons = [
    {"label": "Add event", "action": "components.calendar_test_button", "params": {"source": "selection"}, "variant": "primary"},
    {"label": "Inspect", "action": "components.calendar_test_button", "params": {"source": "inspect"}, "variant": "default"},
]

calendar = sdk.ui.Calendar(
    "calendar_static",
    label="Planning calendar",
    value="2026-03-01",
    min_date="2026-03-01",
    max_date="2026-04-30",
    max_width=None,
    date_format="yyyy-MM-dd",
    input_mask="0000-00-00",
    show_input=True,
    view="month",
    current_date="2026-03-01",
    events=events,
    selected_dates=["2026-03-18"],
    selected_slots=[],
    buttons=buttons,
    action="components.calendar_test_interaction",
    params={"source": "calendar_static"},
    on_event_click="components.calendar_test_event_click",
    on_event_click_params={"source": "calendar_static"},
    time_from=8,
    time_to=18,
)
calendar.set_show_if({
    "conditions": [
        {
            "left": bound.store("/components_test/calendar/show", scope="page", default=True),
            "op": "==",
            "right": True,
        }
    ]
})
calendar.set_hide_if({
    "conditions": [
        {
            "left": bound.store("/components_test/calendar/hide", scope="page", default=False),
            "op": "==",
            "right": True,
        }
    ]
})
calendar.set_required_permissions(["components.complex.view"])
calendar.allow("label.set", "value.set", "current_date.set", "view.set", "events.set", "selected_dates.set", "selected_slots.set", "buttons.set", "time_from.set", "time_to.set")

Bindings and Updates

Store-bound and data-model-bound examples use the same event-calendar state as the static calendar. In Python, use bound.store(...) for page/global store and bound.data(...) for the surface data model. In YAML, use explicit store binding objects and @data/... paths.

Static calendars keep their initial view, current_date, events, and selection. Use store bindings, data-model bindings, or direct property updates when an external control must switch the visible month or replace the event list.

store_calendar = sdk.ui.Calendar("calendar_store", buttons=buttons)
store_calendar.set_property("label", bound.store("/components_test/calendar/label", scope="page", default="Planning calendar"))
store_calendar.set_property("view", bound.store("/components_test/calendar/view", scope="page", default="month"))
store_calendar.set_property("current_date", bound.store("/components_test/calendar/current_date", scope="page", default="2026-03-01"))
store_calendar.set_property("events", bound.store("/components_test/calendar/events", scope="page", default=events))
store_calendar.set_property("selected_dates", bound.store("/components_test/calendar/selected_dates", scope="page", default=["2026-03-18"]))
store_calendar.set_property("selected_slots", bound.store("/components_test/calendar/selected_slots", scope="page", default=[]))

data_calendar = sdk.ui.Calendar("calendar_data", buttons=buttons)
data_calendar.set_property("label", bound.data("/components_test/calendar_model/label", default="Planning calendar"))
data_calendar.set_property("view", bound.data("/components_test/calendar_model/view", default="month"))
data_calendar.set_property("current_date", bound.data("/components_test/calendar_model/current_date", default="2026-03-01"))
data_calendar.set_property("events", bound.data("/components_test/calendar_model/events", default=events))
data_calendar.set_property("selected_dates", bound.data("/components_test/calendar_model/selected_dates", default=["2026-03-18"]))
data_calendar.set_property("selected_slots", bound.data("/components_test/calendar_model/selected_slots", default=[]))

live_calendar = sdk.ui.Calendar("calendar_live", label="Planning calendar", events=events)
live_calendar.allow("label.set", "value.set", "current_date.set", "view.set", "events.set", "selected_dates.set", "selected_slots.set", "buttons.set", "time_from.set", "time_to.set")

Runtime updates must target the current surface:

surface_id = ctx["_surface_id"]

return sdk.effects.respond(
    sdk.effects.ui_messages([
        {
            "stateUpdate": {
                "scope": "page",
                "values": {
                    "/components_test/calendar/label": next_label,
                    "/components_test/calendar/current_date": next_date,
                    "/components_test/calendar/view": next_view,
                    "/components_test/calendar/events": next_events,
                    "/components_test/calendar/selected_dates": next_selected_dates,
                    "/components_test/calendar/selected_slots": next_selected_slots,
                },
            }
        },
        sdk.ui.Builder.build_data_model_update_payload(
            surface_id=surface_id,
            data={
                "components_test": {
                    "calendar_model": {
                        "label": next_label,
                        "current_date": next_date,
                        "view": next_view,
                        "events": next_events,
                        "selected_dates": next_selected_dates,
                        "selected_slots": next_selected_slots,
                    }
                }
            },
        ),
    ]),
    sdk.effects.ui_property_update("calendar_live", "label", next_label, surface_id=surface_id),
    sdk.effects.ui_property_update("calendar_live", "current_date", next_date, surface_id=surface_id),
    sdk.effects.ui_property_update("calendar_live", "view", next_view, surface_id=surface_id),
    sdk.effects.ui_property_update("calendar_live", "events", next_events, surface_id=surface_id),
    sdk.effects.ui_property_update("calendar_live", "selected_dates", next_selected_dates, surface_id=surface_id),
    sdk.effects.ui_property_update("calendar_live", "selected_slots", next_selected_slots, surface_id=surface_id),
)

Interactions

on_event_click is the only dedicated event callback property. It receives the clicked event plus date, time, and title.

The component does not define separate on_day_click, on_hour_click, on_month_change, on_day_change, or on_week_change properties. Use the primary action property for renderer interaction intents.

Custom buttons are shown in the selection bar. The renderer merges each button params with the current selection context:

Active view Button context
Month date
Week date, time, slots as [{date, time}]
Day date, time, slots as ["HH:MM"]

The renderers emit these primary action intents:

Intent Clients When it is emitted Payload fields
navigate Desktop, web Previous/next navigation in month, week, or day view view, direction, date
view_change Desktop, web View tab changes or switching from a month day to day view view, optional date
day_click Desktop, web Day selection in month view view, date
slot_click Desktop, web Time-slot selection in week or day view view, date, time
create_event_request Desktop Context-menu create request in month view view, date, time

create_event_request is emitted by the desktop context menu. On web, use a custom buttons entry such as Add event for the same user flow after a day or slot is selected.

The test page binds every calendar primary action to components.calendar_test_interaction. The action can branch on intent:

@action("calendar_test_interaction")
async def calendar_test_interaction(ctx, session, sdk):
    intent = ctx.get("intent")
    if intent == "navigate":
        view = ctx["view"]
        date = ctx["date"]
    elif intent == "view_change":
        view = ctx["view"]
        date = ctx.get("date")
    elif intent == "day_click":
        date = ctx["date"]
    elif intent == "slot_click":
        date = ctx["date"]
        time = ctx["time"]
    elif intent == "create_event_request":
        date = ctx["date"]
        time = ctx["time"]

Interaction examples reproduced by the test page:

Interaction Demo trigger Example payload
Month change Click previous/next while view is month {"intent": "navigate", "view": "month", "direction": 1, "date": "2026-04-01"}
Week change Click previous/next while view is week {"intent": "navigate", "view": "week", "direction": 1, "date": "2026-03-30"}
Day change Click previous/next while view is day {"intent": "navigate", "view": "day", "direction": 1, "date": "2026-03-24"}
View change Click the month, week, or day tab {"intent": "view_change", "view": "week"}
Month day click Click a day cell in month view {"intent": "day_click", "view": "month", "date": "2026-03-18"}
Week hour click Click a time slot in week view {"intent": "slot_click", "view": "week", "date": "2026-03-23", "time": "09:00"}
Day hour click Click a time slot in day view {"intent": "slot_click", "view": "day", "date": "2026-03-23", "time": "09:30"}
Event click Click an event item {"event": {...}, "date": "2026-03-18", "time": "11:00", "title": "Board review"}
Add event button Select a day or slot, then click Add event {"source": "selection", "date": "2026-03-18", "time": "11:00", "slots": [...]}
Desktop create request Right-click a month day and choose Add event here {"intent": "create_event_request", "view": "month", "date": "2026-03-18", "time": "09:00"}

Screenshots

Desktop:

Calendar desktop preview

Web:

Calendar web preview