ResourcesMonthView

Month view with resource lanes for scheduling across resources

Usage

ResourcesMonthView displays a month grid where each day cell contains resource lanes. Events are shown within their resource's lane, making it easy to see resource utilization across the month.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Static mode

Set mode="static" to disable all interactions.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      mode="static"
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Drag and drop

Enable drag and drop with withEventsDragAndDrop prop. The onEventDrop callback receives the resourceId of the target resource, allowing you to update the event's resource assignment.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView, ScheduleEventData } from '@mantine/schedule';
import { events as initialEvents, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      withEventsDragAndDrop
      onEventDrop={({ eventId, newStart, newEnd, resourceId }) => {
        setEvents((current) =>
          current.map((event) =>
            event.id === eventId
              ? { ...event, start: newStart, end: newEnd, resourceId }
              : event
          )
        );
      }}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Event resize

Enable event resizing with withEventResize prop. Events can be resized by dragging their start or end edges, and the onEventResize callback is called with the updated event start and end dates.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView, ScheduleEventData } from '@mantine/schedule';
import { events as initialEvents, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      withEventResize
      onEventResize={({ eventId, newStart, newEnd }) => {
        setEvents((current) =>
          current.map((event) =>
            event.id === eventId
              ? { ...event, start: newStart, end: newEnd }
              : event
          )
        );
      }}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Resizing snaps to whole days and preserves the event's original time of day: dragging the end edge of an event that ends at 17:00 onto another day keeps the 17:00 end time. Events that end exactly at midnight are treated as ending on the previous day, so their end stays exclusive after a resize.

Resize handles are rendered only on the edges where the event actually starts and ends. An event that continues outside the displayed month, or that is split across rows, does not render a handle on those edges. Events hidden behind the "+N more" indicator cannot be resized.

Resizing never changes the event's resource — drag the event itself to move it to another resource.

Use canResizeEvent to control which events can be resized.

Event form

Click a day cell to create a new event, or click an existing event to edit it. Use withDragSlotSelect and onSlotDragEnd to allow drag-to-create across day cells. The onSlotDragEnd callback includes the resourceId of the resource where the drag started.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { Select } from '@mantine/core';
import { ResourcesMonthView, ScheduleEventData } from '@mantine/schedule';
import { EventData, EventForm } from './EventForm';
import { events as initialEvents, resources } from './data';

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

  const handleDayClick = ({
    date: clickedDate,
    resourceId,
  }: {
    date: string;
    nativeEvent: React.MouseEvent<HTMLButtonElement>;
    resourceId?: string | number;
  }) => {
    setSelectedResourceId(resourceId ? String(resourceId) : null);
    setSelectedEventData({
      title: '',
      start: dayjs(clickedDate).startOf('day').toDate(),
      end: dayjs(clickedDate).endOf('day').toDate(),
      color: 'blue',
    });
    setFormOpened(true);
  };

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

  const handleSlotDragEnd = ({
    rangeStart,
    rangeEnd,
    resourceId,
  }: {
    rangeStart: string;
    rangeEnd: string;
    resourceId?: string | number;
  }) => {
    setSelectedResourceId(resourceId ? String(resourceId) : null);
    setSelectedEventData({
      title: '',
      start: new Date(rangeStart),
      end: new Date(rangeEnd),
      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).toISOString(),
                end: dayjs(values.end).toISOString(),
                color: values.color || 'blue',
                resourceId: selectedResourceId || event.resourceId,
              }
            : event
        )
      );
    } else {
      setEvents((prev) => [
        ...prev,
        {
          id: Math.random().toString(36).substring(2, 11),
          title: values.title,
          start: dayjs(values.start).toISOString(),
          end: dayjs(values.end).toISOString(),
          color: values.color || 'blue',
          resourceId: selectedResourceId || undefined,
        },
      ]);
    }
  };

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

  return (
    <>
      <ResourcesMonthView
        date={date}
        onDateChange={setDate}
        resources={resources}
        events={events}
        withDragSlotSelect
        onDayClick={handleDayClick}
        onSlotDragEnd={handleSlotDragEnd}
        onEventClick={handleEventClick}
        startScrollDate={dayjs().format('YYYY-MM-DD')}
      />

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

Custom event rendering

Use renderEvent prop to customize how events are rendered. The example below uses HoverCard to display event details on hover.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { HoverCard, UnstyledButton } from '@mantine/core';
import { ResourcesMonthView, ScheduleEventData } from '@mantine/schedule';
import { EventDetails } from './EventDetails';
import { events as initialEvents, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      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="right" closeDelay={0} transitionProps={{ duration: 0 }}>
          <HoverCard.Target>
            <UnstyledButton {...props} />
          </HoverCard.Target>
          <HoverCard.Dropdown>
            <EventDetails event={event} resources={resources} />
          </HoverCard.Dropdown>
        </HoverCard>
      )}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Custom resource label

Use renderResourceLabel prop to customize how resource labels are rendered in the row headers.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30

Meeting room: Tokyo

Office

Meeting room: Paris

Office

Meeting room: New York

Office

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

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      renderResourceLabel={(resource: ScheduleResourceData) => (
        <Stack gap={0} align="flex-start">
          <Text fw={600} size="sm">
            {resource.label}
          </Text>
          <Text size="xs" c="dimmed">
            Office
          </Text>
        </Stack>
      )}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

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
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Floor 1
Meeting room: Tokyo
Meeting room: Paris
Floor 2
Meeting room: New York
Overflow room
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView, 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: 'overflow', label: 'Overflow room' },
];

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

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      groups={groups}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Localization

Set locale prop to change the language. Use labels prop to override built-in labels.

Recursos
mar.1
mié.2
jue.3
vie.4
sáb.5
dom.6
lun.7
mar.8
mié.9
jue.10
vie.11
sáb.12
dom.13
lun.14
mar.15
mié.16
jue.17
vie.18
sáb.19
dom.20
lun.21
mar.22
mié.23
jue.24
vie.25
sáb.26
dom.27
lun.28
mar.29
mié.30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import 'dayjs/locale/es';

import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      locale="es"
      labels={{
        day: 'Día',
        week: 'Semana',
        month: 'Mes',
        year: 'Año',
        today: 'Hoy',
        previous: 'Anterior',
        next: 'Siguiente',
        more: 'Más',
        resources: 'Recursos',
        moreLabel: (hiddenEventsCount) => `+${hiddenEventsCount} más`,
      }}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Recurring events

ResourcesMonthView automatically expands recurring events for the visible month. See Recurring events guide for full documentation.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } 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')} 09:30: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} 14:30: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} 12:00:00`,
    color: 'green',
    resourceId: 'paris',
  },
];

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startScrollDate={today}
    />
  );
}

Max events per cell

Use maxEventsPerTimeSlot prop to limit the number of events visible in each cell. When there are more events than the limit, a "+more" indicator is shown.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView, 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[] = [
  { id: 1, title: 'Team Meeting', start: `${today} 09:00:00`, end: `${today} 10:00:00`, color: 'blue', resourceId: 'tokyo' },
  { id: 2, title: 'Code Review', start: `${today} 11:00:00`, end: `${today} 12:00:00`, color: 'green', resourceId: 'tokyo' },
  { id: 3, title: 'Design Review', start: `${today} 13:00:00`, end: `${today} 14:00:00`, color: 'violet', resourceId: 'tokyo' },
  { id: 4, title: 'Sprint Planning', start: `${today} 15:00:00`, end: `${today} 16:00:00`, color: 'orange', resourceId: 'tokyo' },
  { id: 5, title: 'Retrospective', start: `${today} 16:30:00`, end: `${today} 17:30:00`, color: 'cyan', resourceId: 'tokyo' },
  { id: 6, title: 'Client Call', start: `${today} 09:00:00`, end: `${today} 10:00:00`, color: 'pink', resourceId: 'paris' },
  { id: 7, title: 'Workshop', start: `${today} 11:00:00`, end: `${today} 12:00:00`, color: 'grape', resourceId: 'paris' },
  { id: 8, title: 'Standup', start: `${today} 14:00:00`, end: `${today} 15:00:00`, color: 'red', resourceId: 'paris' },
  { id: 9, title: 'Demo', start: `${today} 16:00:00`, end: `${today} 17:00:00`, color: 'teal', resourceId: 'paris' },
];

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      maxEventsPerTimeSlot={3}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Day width and row height

Use dayWidth and rowHeight props to customize the dimensions of day columns and resource rows.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      dayWidth={60}
      rowHeight={64}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Start scroll date

Use startScrollDate prop to scroll to a specific date on initial render. This is useful when the month has many days and you want the view to start at a specific date, for example today.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Without weekend days

Set withWeekendDays={false} to hide weekend day columns from the month grid.

Resources
Tue1
Wed2
Thu3
Fri4
Mon7
Tue8
Wed9
Thu10
Fri11
Mon14
Tue15
Wed16
Thu17
Fri18
Mon21
Tue22
Wed23
Thu24
Fri25
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      withWeekendDays={false}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

More events indicator

When a day cell has more events than maxEventsPerTimeSlot, a "+X more" indicator is shown. Click the indicator to see all events for that day.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView, 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[] = [
  { id: 1, title: 'Team Standup', start: `${today} 08:00:00`, end: `${today} 08:30:00`, color: 'blue', resourceId: 'tokyo' },
  { id: 2, title: 'Sprint Planning', start: `${today} 09:00:00`, end: `${today} 10:00:00`, color: 'green', resourceId: 'tokyo' },
  { id: 3, title: 'Design Review', start: `${today} 10:30:00`, end: `${today} 11:30:00`, color: 'violet', resourceId: 'tokyo' },
  { id: 4, title: 'Code Review', start: `${today} 13:00:00`, end: `${today} 14:00:00`, color: 'orange', resourceId: 'tokyo' },
  { id: 5, title: 'Retrospective', start: `${today} 14:30:00`, end: `${today} 15:30:00`, color: 'cyan', resourceId: 'tokyo' },
  { id: 6, title: 'Client Call', start: `${today} 16:00:00`, end: `${today} 17:00:00`, color: 'pink', resourceId: 'tokyo' },
  { id: 7, title: 'Workshop', start: `${today} 10:00:00`, end: `${today} 11:00:00`, color: 'grape', resourceId: 'paris' },
];

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      maxEventsPerTimeSlot={2}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

More events props

Use moreEventsProps to customize the more events dropdown, for example to use a modal instead of a popover.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView, 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[] = [
  { id: 1, title: 'Team Standup', start: `${today} 08:00:00`, end: `${today} 08:30:00`, color: 'blue', resourceId: 'tokyo' },
  { id: 2, title: 'Sprint Planning', start: `${today} 09:00:00`, end: `${today} 10:00:00`, color: 'green', resourceId: 'tokyo' },
  { id: 3, title: 'Design Review', start: `${today} 10:30:00`, end: `${today} 11:30:00`, color: 'violet', resourceId: 'tokyo' },
  { id: 4, title: 'Code Review', start: `${today} 13:00:00`, end: `${today} 14:00:00`, color: 'orange', resourceId: 'tokyo' },
  { id: 5, title: 'Retrospective', start: `${today} 14:30:00`, end: `${today} 15:30:00`, color: 'cyan', resourceId: 'tokyo' },
  { id: 6, title: 'Client Call', start: `${today} 16:00:00`, end: `${today} 17:00:00`, color: 'pink', resourceId: 'tokyo' },
  { id: 7, title: 'Workshop', start: `${today} 10:00:00`, end: `${today} 11:00:00`, color: 'grape', resourceId: 'paris' },
];

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      maxEventsPerTimeSlot={2}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
      moreEventsProps={{ dropdownType: 'modal', modalTitle: 'All Events' }}
    />
  );
}

Custom header

Set withHeader={false} to hide the default header and use ScheduleHeader to build a custom header with navigation controls.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { DateStringValue, ResourcesMonthView, ScheduleHeader } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <div>
      <ScheduleHeader>
        <ScheduleHeader.Previous
          onClick={() =>
            setDate(
              dayjs(date)
                .subtract(1, 'month')
                .startOf('month')
                .format('YYYY-MM-DD') as DateStringValue
            )
          }
        />
        <ScheduleHeader.MonthYearSelect
          yearValue={dayjs(date).year()}
          monthValue={dayjs(date).month()}
          onYearChange={(year) =>
            setDate(
              dayjs(date)
                .year(year)
                .startOf('month')
                .format('YYYY-MM-DD') as DateStringValue
            )
          }
          onMonthChange={(month) =>
            setDate(
              dayjs(date)
                .month(month)
                .startOf('month')
                .format('YYYY-MM-DD') as DateStringValue
            )
          }
        />
        <ScheduleHeader.Next
          onClick={() =>
            setDate(
              dayjs(date)
                .add(1, 'month')
                .startOf('month')
                .format('YYYY-MM-DD') as DateStringValue
            )
          }
        />
        <ScheduleHeader.Today
          onClick={() =>
            setDate(
              dayjs().format('YYYY-MM-DD') as DateStringValue
            )
          }
        />
      </ScheduleHeader>

      <ResourcesMonthView
        date={date}
        onDateChange={setDate}
        resources={resources}
        events={events}
        withHeader={false}
      />
    </div>
  );
}

Radius

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      radius="md"
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}

Scroll area props

Use scrollAreaProps to customize the scroll area behavior.

Resources
Tue1
Wed2
Thu3
Fri4
Sat5
Sun6
Mon7
Tue8
Wed9
Thu10
Fri11
Sat12
Sun13
Mon14
Tue15
Wed16
Thu17
Fri18
Sat19
Sun20
Mon21
Tue22
Wed23
Thu24
Fri25
Sat26
Sun27
Mon28
Tue29
Wed30
Meeting room: Tokyo
Meeting room: Paris
Meeting room: New York
import dayjs from 'dayjs';
import { useState } from 'react';
import { ResourcesMonthView } from '@mantine/schedule';
import { events, resources } from './data';

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

  return (
    <ResourcesMonthView
      date={date}
      onDateChange={setDate}
      resources={resources}
      events={events}
      scrollAreaProps={{
        scrollbarSize: 10,
        offsetScrollbars: true,
        type: 'always',
        scrollbars: 'x',
      }}
      startScrollDate={dayjs().format('YYYY-MM-DD')}
    />
  );
}