Back to Mantine

Week View

apps/mantine.dev/src/pages/schedule/week-view.mdx

9.6.013.8 KB
Original Source

import { WeekViewDemos } from '@docs/demos'; import { Layout } from '@/layout'; import { MDX_DATA } from '@/mdx';

export default Layout(MDX_DATA.WeekView);

Usage

WeekView displays events for an entire week with time slots. It supports all-day events, overlapping events, drag and drop, custom time ranges, and more.

<Demo data={WeekViewDemos.usage} />

Controlled date

Control the date displayed by WeekView externally using date and onDateChange props.

<Demo data={WeekViewDemos.controlledDate} />

Time range

Use startTime and endTime props to set the visible time range. Times should be in HH:mm:ss format.

<Demo data={WeekViewDemos.timeRange} />

Start scroll time

Use startScrollTime prop to set the initial scroll position to a specific time. The value should be in HH:mm:ss format. This is useful when you want the view to open at a specific time (e.g., business hours start) instead of midnight.

<Demo data={WeekViewDemos.startScrollTime} />

Interval minutes

intervalMinutes prop controls the granularity of time slots. Default is 60 minutes.

<Demo data={WeekViewDemos.intervalMinutes} />

Sub-hour grid lines

By default, WeekView displays a grid line for every time slot. When intervalMinutes is smaller than 60, set withSubHourGridLines={false} to display only one grid line per hour while keeping the smaller interval for creating and resizing events. This is useful to achieve a Google Calendar like layout: events snap to 15 or 30 minutes increments, but the grid stays clean with hourly lines.

<Demo data={WeekViewDemos.subHourGridLines} />

First day of week

Set firstDayOfWeek to control which day starts the week. 0 is Sunday, 1 is Monday (default), etc.

<Demo data={WeekViewDemos.firstDayOfWeek} />

Weekday format

Use weekdayFormat prop to customize the weekday names display. It accepts dayjs format strings.

<Demo data={WeekViewDemos.weekdayFormat} />

Without weekend days

Set withWeekendDays={false} to hide Saturday and Sunday columns.

<Demo data={WeekViewDemos.withoutWeekendDays} />

Highlight today

Set highlightToday to visually distinguish today's column:

<Demo data={WeekViewDemos.highlightToday} />

Without week number

Set withWeekNumber={false} to hide the week number in the top-left corner.

<Demo data={WeekViewDemos.withoutWeekNumber} />

Current time indicator

Set withCurrentTimeIndicator to display a line showing the current time on today's column.

<Demo data={WeekViewDemos.currentTimeIndicator} />

Force current time indicator

Set forceCurrentTimeIndicator to display the current time indicator on the same day of week even when viewing a different week. This is useful to give users a sense of the current time position relative to their schedule.

<Demo data={WeekViewDemos.forceCurrentTimeIndicator} />

Current time indicator in a different timezone

@mantine/schedule works with timezone-agnostic YYYY-MM-DD HH:mm:ss strings and does not perform any timezone conversions on its own. By default, the current time indicator is positioned based on the user's local time.

To display the indicator in a different timezone, use the getCurrentTime prop. It is a function that returns the current time and is called on every tick, so the indicator keeps updating automatically. In the example below, the current time is converted to the selected timezone with the dayjs timezone plugin – switch the timezone to see the indicator and the time bubble move to the matching day and position:

<Demo data={WeekViewDemos.timezone} />

Without all-day slots

Set withAllDaySlots={false} to hide the all-day events section at the top.

<Demo data={WeekViewDemos.withoutAllDaySlots} />

All-day events

All-day events are displayed in a separate section at the top of the week view. Events that span midnight or cover a full day are automatically placed in this section.

<Demo data={WeekViewDemos.allDayEvents} />

Without header

Set withHeader={false} to hide the header controls.

<Demo data={WeekViewDemos.withoutHeader} />

View change callback

Use onViewChange callback to be notified when the user selects a different view from the header dropdown.

<Demo data={WeekViewDemos.viewChange} />

Custom header

You can build a custom header using ScheduleHeader compound components combined with your own controls. Set withHeader={false} on the view and compose the header externally.

<Demo data={WeekViewDemos.customHeader} />

Week label format

Use weekLabelFormat prop to customize the week range display in the header.

<Demo data={WeekViewDemos.weekLabelFormat} />

Slot label format

slotLabelFormat prop controls the format of time labels.

<Demo data={WeekViewDemos.slotLabelFormat} />

Slot height

Customize the height of time slots and the all-day section using slotHeight and allDaySlotHeight props.

<Demo data={WeekViewDemos.slotHeight} />

Radius

Use radius prop to customize the border radius of events.

<Demo data={WeekViewDemos.radius} />

Business hours

Use highlightBusinessHours and businessHours props to visually distinguish business hours.

<Demo data={WeekViewDemos.businessHours} />

Business hours per day

Pass an object to businessHours to configure the range for each day of the week individually. Keys are day numbers (0 – Sunday, 6 – Saturday). Days missing from the object or set to null are marked as fully outside business hours:

<Demo data={WeekViewDemos.businessHoursPerDay} />

Custom time slot props

Use getTimeSlotProps to add custom props to individual time slots based on their time range. The function receives { start, end } datetime strings in YYYY-MM-DD HH:mm:ss format and should return an object of props to spread onto the slot element, or undefined.

This is useful for setting data-business-hours on a custom range that differs from the default 9:00–17:00, or for attaching custom event handlers to specific slots. Event handlers like onClick returned by getTimeSlotProps are composed with internal handlers (onTimeSlotClick) – both will fire without overriding each other.

<Demo data={WeekViewDemos.getTimeSlotProps} />

Overlapping events

When multiple events overlap in time, they are automatically positioned side by side.

<Demo data={WeekViewDemos.overlappingEvents} />

Drag and drop

Enable drag and drop by setting withDragDrop prop. Events can be dragged to different days and times.

<Demo data={WeekViewDemos.dragDrop} />

Drag interval

By default events snap to intervalMinutes when moved by drag and drop. Set eventDragInterval to use a different snap step for dragging – for example, a grid with 30-minute slots whose events can be moved in 15-minute increments. A ghost preview shows where the event will land:

<Demo data={WeekViewDemos.eventDragInterval} />

Restrict draggable events

Use canDragEvent callback to control which events can be dragged. Events that return false will not be draggable.

<Demo data={WeekViewDemos.canDragEvent} />

External drag and drop

Use onExternalEventDrop to allow dragging items from outside the component into the schedule. External items must set data in dataTransfer during their onDragStart. The callback receives the DataTransfer object and the drop target datetime.

<Demo data={WeekViewDemos.externalDragDrop} />

Bidirectional drag and drop

Combine onExternalEventDrop with withEventsDragAndDrop to enable bidirectional drag and drop. Items dragged from the sidebar are removed from the list and added to the schedule. Events dragged from the schedule back to the sidebar are removed from the schedule. The schedule sets application/json with { eventId } in dataTransfer when an event is dragged, which the sidebar drop zone reads to identify the event.

<Demo data={WeekViewDemos.bidirectionalDragDrop} />

Event resize

Enable event resizing by setting withEventResize prop. Users can drag the top or bottom edge of an event to adjust its start or end time. Use onEventResize callback to handle the resize. Use canResizeEvent to control which events can be resized.

<Demo data={WeekViewDemos.eventResize} />

Resize interval

By default events snap to intervalMinutes when resized. Set eventResizeInterval to use a different snap step for resizing – for example, a grid with 30-minute slots whose events can be resized in 15-minute increments:

<Demo data={WeekViewDemos.eventResizeInterval} />

Restrict resizable events

Use canResizeEvent callback to control which events can be resized. Events that return false will not show resize handles.

<Demo data={WeekViewDemos.canResizeEvent} />

Full event customization

Use renderEvent prop to fully customize event rendering. This function receives the event data as the first argument and all props that would be passed to the event root element (including children) as the second argument, allowing you to wrap events in custom components like HoverCard, Tooltip, or custom wrappers.

<Demo data={WeekViewDemos.renderEvent} />

Custom event body

Use renderEventBody prop to customize the content inside events without replacing the event wrapper. This is useful for adding icons, additional text, or custom layouts.

<Demo data={WeekViewDemos.renderEventBody} />

Recurring events

WeekView automatically expands recurring events for the visible week. See Recurring events guide for full documentation.

<Demo data={WeekViewDemos.recurringEvents} />

Background events

Set display="background" on an event to render it as a full-width, semi-transparent block behind regular events. By default it cannot be clicked, dragged, or resized. Background events are useful for marking unavailability, lunch breaks, focus time, or other blocked periods.

<Demo data={WeekViewDemos.backgroundEvents} />

Interactive background events

Set withInteractiveBackgroundEvents prop to make background events clickable. Clicking a background event calls onEventClick with the event object, the same as for regular events – use event.display === 'background' to tell them apart in the handler.

Note that an interactive background event covers the time slots underneath it: clicks and drag-to-select in its range go to the event instead of the grid. Background events still cannot be dragged or resized.

<Demo data={WeekViewDemos.interactiveBackgroundEvents} />

Custom background event styles with drag and drop blocking

Use Styles API to customize background event appearance and prevent dropping regular events into blocked time ranges. This example uses diagonal red lines to indicate lunch breaks across the entire week and rejects drops that overlap with background events.

<Demo data={WeekViewDemos.backgroundEventsCustomStyle} />

Agenda view

Set withAgenda prop to display an "Agenda" button in the header. When clicked, it opens an AgendaView showing events for the current week as a list.

<Demo data={WeekViewDemos.withAgenda} />

Static mode

Set mode="static" to disable all interactions.

<Demo data={WeekViewDemos.staticMode} />

Localization

Use locale prop to set the dayjs locale for date formatting. Combine it with labels prop to translate all UI text.

<Demo data={WeekViewDemos.localization} />

Create and update events

Set withDragSlotSelect prop to allow users to drag across time slots to select a time range. When the drag ends, the onSlotDragEnd callback is called with the range start and end dates. The drag is constrained to a single day column. Combined with onTimeSlotClick, onAllDaySlotClick, and onEventClick callbacks, this enables a complete event creation and editing experience.

<Demo data={WeekViewDemos.eventForm} />

Responsive styles

WeekView uses @container queries for responsive styles. The component automatically adjusts its layout based on the container width, hiding labels and reducing padding on smaller screens. Container queries are supported in all modern browsers.

Accessibility

Focus management

In the WeekView component, focus is managed to provide an efficient keyboard navigation experience:

  • The weekdays row, all-day slots row, and time slots grid each have their first element in the tab order (tabIndex={0})
  • All other elements have tabIndex={-1} and can only be reached via arrow key navigation
  • This approach reduces the number of tab stops when navigating through the schedule

Keyboard interactions

Weekdays row:

<KeyboardEventsTable data={[ { key: 'ArrowRight', description: 'Focuses next weekday', }, { key: 'ArrowLeft', description: 'Focuses previous weekday', }, ]} />

All-day slots (when enabled):

<KeyboardEventsTable data={[ { key: 'ArrowRight', description: 'Focuses next all-day slot', }, { key: 'ArrowLeft', description: 'Focuses previous all-day slot', }, { key: 'ArrowDown', description: 'Focuses first time slot of the same day', }, ]} />

Time slots:

<KeyboardEventsTable data={[ { key: 'ArrowRight', description: 'Focuses same time slot in the next day', }, { key: 'ArrowLeft', description: 'Focuses same time slot in the previous day', }, { key: 'ArrowDown', description: 'Focuses next time slot in the same day', }, { key: 'ArrowUp', description: 'Focuses previous time slot (or all-day slot if on first time slot and all-day slots are enabled)', }, ]} />

Slot labels

Each time slot button has an aria-label attribute with the complete slot information including the date and time range (e.g., "Time slot 2025-11-03 08:00:00 - 09:00:00"). All-day slots have labels like "All day 2025-11-03", and weekday buttons have labels like "Weekday 2025-11-03". This provides screen reader users with complete context about each element.