# Navigation > Navigate the dash-mui-scheduler EventCalendar through time by setting visibleDate, with Prev / Today / Next buttons computed in Python. --- .. llms_copy::Navigation .. toc:: ### Navigation Every scheduler component shows a single window of time — a day, a week, a month. Which window is on screen is governed by one prop: **`visibleDate`**, an ISO date **string** such as `"2024-01-15"`. To move forwards or backwards in time you simply hand the component a *new* `visibleDate`. .. admonition::There is no apiRef in Dash :color: blue In the React MUI X Scheduler you would call methods on an `apiRef` to jump around. Dash has no imperative ref — you navigate **declaratively** by setting `visibleDate`. Compute the next date in Python (with `datetime` / `timedelta`), return it as an ISO string, and the calendar re-renders on that window. Dates crossing the boundary are always plain strings, never Python `datetime` objects. ### Default visible date — `defaultVisibleDate` `defaultVisibleDate` is the **uncontrolled** way to pick the opening window. Set it once and the component manages the visible date from then on — the built-in navigation arrows move it and Dash never hears about the changes. Use this when you only need to land the user on the right week at load time: ```python dms.EventCalendar( id="my-cal", events=events, defaultVisibleDate="2024-01-15", defaultView="week", ) ``` Because the events in these docs cluster around the week of **15 Jan 2024**, seeding the visible date there means they are on screen the moment the page loads. ### Controlling the visible date — `visibleDate` `visibleDate` is the **controlled** counterpart and it is wired **IN and OUT**: - **IN** — whatever ISO string you pass becomes the window the component shows. - **OUT** — when the user clicks the component's own ‹ › arrows (or the Today button in its toolbar), the component writes the new ISO date *back* to Dash. Pick `visibleDate` (not `defaultVisibleDate`) whenever Python needs to drive or observe the date — for example to build your own navigation chrome, sync two calendars, or display the current window elsewhere on the page. Don't mix the two on the same component: a controlled `visibleDate` wins. ### Prev / Today / Next in Python The example below replaces the toolbar arrows with three `dmc.Button`s. Each click reads the current `visibleDate`, computes a new one with Python's `datetime` module, and returns it: - **Prev** / **Next** parse the current ISO string with `date.fromisoformat`, shift it by `timedelta(weeks=1)`, and re-serialise with `.isoformat()`. - **Today** returns `date.today().isoformat()`. A `dmc.Text` below the buttons reads `visibleDate` back out, so you can watch the value change whether you click your own buttons *or* the calendar's built-in arrows — both feed the same controlled prop. .. admonition::Why visibleDate is also an Input :color: green The navigate callback takes `visibleDate` as an `Input` as well as an `Output`. That lets the *same* prop carry the calendar's built-in arrow presses through to Python: when the trigger is the calendar itself we just echo the value back, otherwise we compute the shifted date. The callback is `prevent_initial_call=True` so the seeded `"2024-01-15"` is left untouched on load. .. exec::docs.navigation.navigation_buttons ```python # File: docs/navigation/navigation_buttons.py from datetime import date, timedelta from dash import Input, Output, callback import dash_mantine_components as dmc import dash_mui_scheduler as dms # `visibleDate` is an ISO date STRING (e.g. "2024-01-15"). It is controlled # IN *and* OUT: we hand the calendar a value, and the calendar also writes the # date back when the user navigates with the built-in arrows. Because there is # no apiRef in Dash, you move through time purely by *setting* visibleDate. events = [ { "id": "1", "title": "Sprint planning", "start": "2024-01-15T09:00:00", "end": "2024-01-15T10:30:00", "color": "blue", }, { "id": "2", "title": "Design review", "start": "2024-01-16T13:00:00", "end": "2024-01-16T14:00:00", "color": "purple", }, { "id": "3", "title": "Retro", "start": "2024-01-18T15:00:00", "end": "2024-01-18T16:00:00", "color": "green", }, ] # Seed the controlled value so the calendar opens on the week of the events. INITIAL_DATE = "2024-01-15" component = dmc.Stack( [ dmc.Group( [ dmc.Button("‹ Prev", id="navigation-prev", variant="default"), dmc.Button("Today", id="navigation-today", variant="light"), dmc.Button("Next ›", id="navigation-next", variant="default"), ], gap="xs", ), dmc.Text(id="navigation-readout", size="sm", c="dimmed"), dms.EventCalendar( id="navigation-cal", events=events, visibleDate=INITIAL_DATE, defaultView="week", height=600, ), ], gap="sm", ) @callback( Output("navigation-cal", "visibleDate"), Input("navigation-prev", "n_clicks"), Input("navigation-next", "n_clicks"), Input("navigation-today", "n_clicks"), Input("navigation-cal", "visibleDate"), prevent_initial_call=True, ) def navigate(prev_clicks, next_clicks, today_clicks, visible_date): from dash import ctx trigger = ctx.triggered_id # The calendar's own arrows already updated visibleDate -> nothing to do. if trigger == "navigation-cal": return visible_date if trigger == "navigation-today": return date.today().isoformat() # Parse the current ISO date string, shift by one week, re-serialize. current = date.fromisoformat((visible_date or INITIAL_DATE)[:10]) if trigger == "navigation-prev": return (current - timedelta(weeks=1)).isoformat() if trigger == "navigation-next": return (current + timedelta(weeks=1)).isoformat() return visible_date @callback( Output("navigation-readout", "children"), Input("navigation-cal", "visibleDate"), ) def show_visible_date(visible_date): return f"Current visibleDate: {visible_date or INITIAL_DATE}" ``` ### EventCalendar props `visibleDate`, `defaultVisibleDate`, `view`, and `defaultView` follow the same controlled / uncontrolled pattern. The full prop reference: .. kwargs::dash_mui_scheduler.EventCalendar --- *Source: /navigation*