ResourcesWeekView

Week view with resource rows for scheduling across resources

Usage

ResourcesWeekView displays resources as rows and a full week of time slots as columns with a two-level header showing day names and time labels. Each row represents a resource (e.g., conference room, person, equipment) and shows events assigned to that resource via the resourceId property on event data.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
    />
  );
}

All-day events

Events that span a whole day (start at 00:00:00 and end at the next day 00:00:00) are rendered as full-width bars within their day column. Foreground all-day events are pinned to the top of the column and stack when there are several; all-day events with display: 'background' tint the whole day column.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Maintenance
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
    />
  );
}

Drag and drop

Enable cross-resource drag and drop with withEventsDragAndDrop prop. The onEventDrop callback receives the target resourceId as the fifth argument, allowing you to update the event's resource assignment. Events can be dragged across both resources and days.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView, ScheduleEventData } from '@mantine/schedule';
import { events as initialEvents, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);
  const [events, setEvents] = useState<ScheduleEventData[]>(initialEvents);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      withEventsDragAndDrop
      onEventDrop={({ eventId, newStart, newEnd, resourceId }) => {
        setEvents((current) =>
          current.map((event) =>
            event.id === eventId
              ? { ...event, start: newStart, end: newEnd, resourceId }
              : event
          )
        );
      }}
    />
  );
}

Event form

Use onTimeSlotClick, onSlotDragEnd, and onEventClick callbacks to open a form for creating or editing events. Combine with withDragSlotSelect to allow selecting a time range by dragging across slots.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { Select } from '@mantine/core';
import { ResourcesWeekView, ScheduleEventData } from '@mantine/schedule';
import { EventData, EventForm } from './EventForm';
import { events as initialEvents, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);
  const [events, setEvents] = useState<ScheduleEventData[]>(initialEvents);
  const [formOpened, setFormOpened] = useState(false);
  const [selectedEventData, setSelectedEventData] = useState<EventData | null>(null);
  const [selectedResourceId, setSelectedResourceId] = useState<string | null>(
    String(resources[0].id)
  );

  const handleTimeSlotClick = (
    slotStart: string,
    slotEnd: string,
    _e: React.MouseEvent,
    resourceId?: string | number
  ) => {
    setSelectedResourceId(resourceId ? String(resourceId) : String(resources[0].id));
    setSelectedEventData({
      title: '',
      start: new Date(slotStart),
      end: new Date(slotEnd),
      color: 'blue',
    });
    setFormOpened(true);
  };

  const handleEventClick = (event: ScheduleEventData) => {
    setSelectedResourceId(event.resourceId ? String(event.resourceId) : String(resources[0].id));
    setSelectedEventData({
      id: event.id,
      title: event.title,
      start: new Date(event.start),
      end: new Date(event.end),
      color: event.color || 'blue',
    });
    setFormOpened(true);
  };

  const handleSubmit = (values: EventData) => {
    if (values.id) {
      setEvents((prev) =>
        prev.map((event) =>
          event.id === values.id
            ? {
                ...event,
                title: values.title,
                start: dayjs(values.start).format('YYYY-MM-DD HH:mm:ss'),
                end: dayjs(values.end).format('YYYY-MM-DD HH:mm:ss'),
                color: values.color || 'blue',
                resourceId: selectedResourceId || resources[0].id,
              }
            : event
        )
      );
    } else {
      setEvents((prev) => [
        ...prev,
        {
          id: Date.now(),
          title: values.title,
          start: dayjs(values.start).format('YYYY-MM-DD HH:mm:ss'),
          end: dayjs(values.end).format('YYYY-MM-DD HH:mm:ss'),
          color: values.color || 'blue',
          resourceId: selectedResourceId || resources[0].id,
        },
      ]);
    }
  };

  const handleSlotDragEnd = (
    rangeStart: string,
    rangeEnd: string,
    resourceId?: string | number
  ) => {
    setSelectedResourceId(resourceId ? String(resourceId) : String(resources[0].id));
    setSelectedEventData({
      title: '',
      start: new Date(rangeStart),
      end: new Date(rangeEnd),
      color: 'blue',
    });
    setFormOpened(true);
  };

  const handleDeleteEvent = () => {
    if (selectedEventData?.id) {
      setEvents((prev) => prev.filter((event) => event.id !== selectedEventData.id));
    }
  };

  return (
    <>
      <ResourcesWeekView
        date={date}
        onDateChange={setDate}
        resources={resources}
        events={events}
        startTime="08:00:00"
        endTime="18:00:00"
        startScrollDateTime={`${today} 08:00:00`}
        withDragSlotSelect
        onTimeSlotClick={handleTimeSlotClick}
        onSlotDragEnd={handleSlotDragEnd}
        onEventClick={handleEventClick}
      />

      <EventForm
        opened={formOpened}
        onClose={() => setFormOpened(false)}
        onExitTransitionEnd={() => setSelectedEventData(null)}
        values={selectedEventData}
        onSubmit={handleSubmit}
        onDelete={selectedEventData?.id ? handleDeleteEvent : undefined}
      >
        <Select
          label="Conference Room"
          placeholder="Select a room"
          radius="md"
          data={resources.map((r) => ({ value: String(r.id), label: String(r.label) }))}
          value={selectedResourceId}
          onChange={setSelectedResourceId}
        />
      </EventForm>
    </>
  );
}

Time range and intervals

Use startTime, endTime and intervalMinutes props to control the visible time range and slot granularity.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="09:00:00"
      endTime="17:00:00"
      intervalMinutes={30}
      startScrollDateTime={`${today} 09:00:00`}
    />
  );
}

Current time indicator

Use withCurrentTimeIndicator to display a line at the current time. Set withCurrentTimeBubble={false} to hide the time bubble label.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'));

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="00:00:00"
      endTime="23:59:59"
      withCurrentTimeIndicator
      withCurrentTimeBubble={false}
    />
  );
}

First day of week

Use firstDayOfWeek to set the first day of the week. Set weekdayFormat to customize the day label format.

Resources
Sunday 21
Monday 22
Tuesday 23
Wednesday 24
Thursday 25
Friday 26
Saturday 27
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'));

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      firstDayOfWeek={0}
      withWeekendDays
      weekdayFormat="dddd D"
    />
  );
}

Custom week label

Use renderWeekLabel to fully customize the week label in the header. When provided, it takes full control of the label. Use weekLabelFormat instead if you only need to change the date format.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'));

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      renderWeekLabel={({ weekStart, weekEnd }) =>
        `Week of ${dayjs(weekStart).format('MMM D')} – ${dayjs(weekEnd).format('MMM D, YYYY')}`
      }
    />
  );
}

Business hours

Use highlightBusinessHours prop to visually distinguish business hours from non-business hours across all time slot columns.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
19:19
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="07:00:00"
      endTime="20:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      highlightBusinessHours
      businessHours={['09:00:00', '17:00:00']}
    />
  );
}

Without weekend days

Set withWeekendDays={false} to hide weekend days from the view.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      withWeekendDays={false}
    />
  );
}

Custom resource label

Use renderResourceLabel prop to customize how resource labels are rendered.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00

Meeting room: Tokyo

Floor 2

Meeting room: Paris

Floor 2

Meeting room: New York

Floor 2

Meeting room: London

Floor 2

import dayjs from 'dayjs';
import { useState } from 'react';
import { Stack, Text } from '@mantine/core';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      renderResourceLabel={(resource) => (
        <Stack gap={2} align="flex-start">
          <Text size="sm" fw={600}>{resource.label}</Text>
          <Text size="xs" c="dimmed">Floor 2</Text>
        </Stack>
      )}
    />
  );
}

Resource groups

Use groups prop to group resources under labeled headers. The group labels are displayed as a column to the left of resource labels, spanning vertically across their resources. Use renderGroupLabel to customize group label rendering and groupLabelWidth to control the group column width.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Floor 1
Meeting room: Tokyo
Meeting room: Paris
Floor 2
Meeting room: New York
Meeting room: London
Overflow room
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView, ScheduleResourceGroup } from '@mantine/schedule';
import { events } from './data';

const resources = [
  { id: 'tokyo', label: 'Meeting room: Tokyo' },
  { id: 'paris', label: 'Meeting room: Paris' },
  { id: 'new-york', label: 'Meeting room: New York' },
  { id: 'london', label: 'Meeting room: London' },
  { id: 'overflow', label: 'Overflow room' },
];

const groups: ScheduleResourceGroup[] = [
  { label: 'Floor 1', resourceIds: ['tokyo', 'paris'] },
  { label: 'Floor 2', resourceIds: ['new-york', 'london'] },
];

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      groups={groups}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
    />
  );
}

Custom event rendering

Use renderEvent prop to customize how events are rendered. The example below shows event details in a hover card.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import { useState } from 'react';
import dayjs from 'dayjs';
import { HoverCard, UnstyledButton } from '@mantine/core';
import { ResourcesWeekView, ScheduleEventData } from '@mantine/schedule';
import { EventDetails } from './EventDetails';
import { events as initialEvents, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);
  const [events, setEvents] = useState<ScheduleEventData[]>(initialEvents);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      withEventsDragAndDrop
      onEventDrop={({ eventId, newStart, newEnd, resourceId }) => {
        setEvents((current) =>
          current.map((event) =>
            event.id === eventId
              ? { ...event, start: newStart, end: newEnd, resourceId }
              : event
          )
        );
      }}
      renderEvent={(event, props) => (
        <HoverCard width={280} position="bottom" closeDelay={0} transitionProps={{ duration: 0 }}>
          <HoverCard.Target>
            <UnstyledButton {...props} />
          </HoverCard.Target>
          <HoverCard.Dropdown>
            <EventDetails event={event} />
          </HoverCard.Dropdown>
        </HoverCard>
      )}
    />
  );
}

Recurring events

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

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');

const resources = [
  { id: 'tokyo', label: 'Meeting room: Tokyo' },
  { id: 'paris', label: 'Meeting room: Paris' },
];

const events = [
  {
    id: 'daily-sync-series',
    title: 'Daily sync (series)',
    start: `${dayjs(today).subtract(2, 'day').format('YYYY-MM-DD')} 09:00:00`,
    end: `${dayjs(today).subtract(2, 'day').format('YYYY-MM-DD')} 11:00:00`,
    color: 'blue',
    resourceId: 'tokyo',
    recurrence: {
      rrule: 'FREQ=DAILY;COUNT=10',
      exdate: [`${today} 09:00:00`],
    },
  },
  {
    id: 'daily-sync-override',
    title: 'Daily sync (moved today)',
    start: `${today} 14:00:00`,
    end: `${today} 16:00:00`,
    color: 'grape',
    resourceId: 'tokyo',
    recurringEventId: 'daily-sync-series',
    recurrenceId: `${today} 09:00:00`,
  },
  {
    id: 'one-off',
    title: 'One-off planning',
    start: `${today} 11:00:00`,
    end: `${today} 13:00:00`,
    color: 'green',
    resourceId: 'paris',
  },
];

function Demo() {
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
    />
  );
}

Max events per time slot

Use maxEventsPerTimeSlot prop to limit the number of visible overlapping events per time slot. When events exceed the limit, a "+N more" indicator is displayed. Clicking the indicator opens a popover with all events in the group. Use moreEventsProps to customize the popover behavior.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView, ScheduleEventData, ScheduleResourceData } from '@mantine/schedule';

const today = dayjs().format('YYYY-MM-DD');

const resources: ScheduleResourceData[] = [
  { id: 'tokyo', label: 'Meeting room: Tokyo' },
  { id: 'paris', label: 'Meeting room: Paris' },
];

const events: ScheduleEventData[] = [
  // ... many overlapping events per resource
];

function Demo() {
  const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'));

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      maxEventsPerTimeSlot={2}
    />
  );
}

Localization

Use locale prop to set the locale for date formatting and labels prop to override default labels.

Recursos
lun. 22
mar. 23
mié. 24
jue. 25
vie. 26
sáb. 27
dom. 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import 'dayjs/locale/es';
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      locale="es"
      labels={{
        day: 'Día',
        week: 'Semana',
        month: 'Mes',
        year: 'Año',
        allDay: 'Todo el día',
        timeSlot: 'Franja horaria',
        today: 'Hoy',
        previous: 'Anterior',
        next: 'Siguiente',
        resources: 'Recursos',
      }}
    />
  );
}

Radius

Use radius prop to change the border radius of events.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      radius="md"
    />
  );
}

Start scroll date time

Use startScrollDateTime prop to scroll to a specific time on mount.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
00:00
01:00
02:00
03:00
04:00
05:00
06:00
07:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
18:00
19:00
20:00
21:00
22:00
23:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
19:19
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startScrollDateTime={`${today} 10:00:00`}
    />
  );
}

Scroll area props

Use scrollAreaProps to pass props to the underlying ScrollArea component.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      scrollAreaProps={{
        scrollbarSize: 10,
        offsetScrollbars: true,
      }}
    />
  );
}

Event resize

Note that event resize is not supported in the week view.

Static mode

Set mode="static" to disable all interactions. Events and time slots become non-interactive, useful for display-only views.

Resources
Mon 22
Tue 23
Wed 24
Thu 25
Fri 26
Sat 27
Sun 28
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
08:00
09:00
10:00
11:00
12:00
13:00
14:00
15:00
16:00
17:00
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
Meeting room: London
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesWeekView } from '@mantine/schedule';
import { events, resources } from './data';

function Demo() {
  const today = dayjs().format('YYYY-MM-DD');
  const [date, setDate] = useState(today);

  return (
    <ResourcesWeekView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startTime="08:00:00"
      endTime="18:00:00"
      startScrollDateTime={`${today} 08:00:00`}
      mode="static"
    />
  );
}