---
title: "React Timeline Multi-Classroom Timetable Example | Mobiscroll"
component: "Timeline"
framework: "React"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/react/timeline/multi-classroom-timetable"
---

# Multi-Classroom Timetable - React Timeline demo

Build a weekly classroom timetable with the React Timeline — rooms and days listed vertically with hourly slots from 8 AM to 8 PM, Monday to Friday. For React and Next.JS.

- [Live demo](https://demo.mobiscroll.com/react/timeline/multi-classroom-timetable)
- [View React JS code on GitHub](https://github.com/acidb/mobiscroll-demos-react/tree/main/src/demos/eventcalendar/timeline/multi-classroom-timetable)
- [View React TS code on GitHub](https://github.com/acidb/mobiscroll-demos-react-ts/tree/main/src/demos/eventcalendar/timeline/multi-classroom-timetable)
- This demo in other frameworks: [JavaScript](https://demo.mobiscroll.com/javascript/timeline/multi-classroom-timetable.md), [jQuery](https://demo.mobiscroll.com/jquery/timeline/multi-classroom-timetable.md), [Angular](https://demo.mobiscroll.com/angular/timeline/multi-classroom-timetable.md), [Vue](https://demo.mobiscroll.com/vue/timeline/multi-classroom-timetable.md)

## Description

While the timeline can easily render multiple days horizontally with hourly resolutions, in some situations it makes sense to multiply the vertical scrolling height and set a [`resolutionVertical`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-view) to day even if working with multiple resources.

To render a timetable for multiple classrooms for a whole week the horizontal timeline can be reduced from 8AM to 8PM and days along with the classrooms can be listed vertically Monday to Friday.

Use the `resolutionVertical` and `startTime`/`endTime` properties in combination with the `startDay`/`endDay` properties of the timeline to set such a view up.

## What this demo shows

- A desktop weekly classroom timetable layout with Monday to Friday workdays, repeated room resources on the vertical axis, and working hours on the horizontal axis.
- **Header navigation** The month and year label in the top-left opens date navigation, while the previous and next arrows and the Today button move between weeks or return to the current day.
- **Time grid** The fixed strip below the header shows working hours from 8 AM to 8 PM in hourly columns.
- **Vertical week view** The strip on the left shows the selected work week from Monday to Friday.
- **Resources** Room resources are repeated in each day, with Green Hall, White Hall, Red Hall, Blue Hall, and Yellow Hall shown for every weekday.
- **Current time** The current time is shown with a vertical blue line and a time label.
- **Hover behavior** Hovering over the time grid shows a time indicator that follows the cursor in 15-minute increments.
- **Event cards** Events are rendered as colored cards with a colored left stripe, the course name in bold, the professor name in bold light gray text, and the student year level.
- **Event positioning** Events are placed by resource, date, start time, and end time.
- **Event overlapping** Overlapping events are stacked within the resource row so they remain visible, with the row height increasing as needed.
- **Event creation** New events can be created by double-clicking in the timeline or by clicking and dragging across a time range.
- **Event interaction** Events highlight on hover and show drag and resize handles for moving or changing the event duration.
- **Event selection** Clicking an event selects and highlights it.
- **Vertical scrolling** The resource area scrolls vertically so the timeline can display many repeated room rows.

## Best for

- **School timetables** Weekly class schedules where courses need to be organized by day, time, and classroom.
- **University course scheduling** Multi-room academic schedules with parallel classes, professors, and student year levels.
- **Conference room planning** Room-based schedules where each location needs its own row for every workday.
- **Classroom management** Timetables that need to show room usage across a Monday to Friday week.
- **Facility scheduling** Resource planning scenarios where events are grouped by both date and location.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-themeVariant) - option
- [`clickToCreate`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-clickToCreate) - option
- [`dragToCreate`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-dragToCreate) - option
- [`dragToMove`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-dragToMove) - option
- [`dragToResize`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-dragToResize) - option
- [`eventDelete`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-eventDelete) - option
- [`view`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-view) - option
- [`data`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-data) - option
- [`resources`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-resources) - option
- [`renderTimelineDay`](https://mobiscroll.com/docs/react/eventcalendar/api#renderer-renderTimelineDay) - renderer
- [`renderTimelineEventContent`](https://mobiscroll.com/docs/react/eventcalendar/api#renderer-renderTimelineEventContent) - renderer
- [`extendDefaultEvent`](https://mobiscroll.com/docs/react/eventcalendar/api#opt-extendDefaultEvent) - option

## Code

### JSX

```jsx
import { Eventcalendar, formatDate, getJson, setOptions } from '@mobiscroll/react';
import { useCallback, useEffect, useMemo, useState } from 'react';

setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

function App() {
  const [myEvents, setEvents] = useState([]);

  const myView = useMemo(
    () => ({
      timeline: {
        type: 'week',
        startDay: 1,
        endDay: 5,
        startTime: '08:00',
        endTime: '20:00',
        resolutionHorizontal: 'hour',
        resolutionVertical: 'day',
      },
    }),
    [],
  );

  const myResources = useMemo(
    () => [
      {
        id: 1,
        name: 'Green Hall',
      },
      {
        id: 2,
        name: 'White Hall',
      },
      {
        id: 3,
        name: 'Red Hall',
      },
      {
        id: 4,
        name: 'Blue Hall',
      },
      {
        id: 5,
        name: 'Yellow Hall',
      },
    ],
    [],
  );

  const myCustomDay = useCallback((day) => {
    const date = day.date;
    return (
      <div className="md-timetable-day">
        <div className="md-timetable-day-name">{formatDate('DDDD', date)}</div>
        <div>{formatDate('MM/DD/YYY', date)}</div>
      </div>
    );
  }, []);

  const myCustomEvent = useCallback(
    (args) => (
      <div>
        <div className="md-timetable-event-title">{args.title}</div>
        <div className="md-timetable-event-prop">Prof. {args.original.prof}</div>
        <div className="md-timetable-event-class">{args.original.class} year</div>
      </div>
    ),
    [],
  );

  const myDefaultEvent = useCallback(
    () => ({
      title: 'New class',
      prof: 'Stacia Jaden',
      class: 'Junior',
      color: '#ff0000',
    }),
    [],
  );

  useEffect(() => {
    getJson(
      'https://trial.mobiscroll.com/timetable-events/',
      (events) => {
        setEvents(events);
      },
      'jsonp',
    );
  }, []);

  return (
    <Eventcalendar
      className="md-timetable"
      clickToCreate={true}
      dragToCreate={true}
      dragToMove={true}
      dragToResize={true}
      eventDelete={true}
      view={myView}
      data={myEvents}
      resources={myResources}
      renderTimelineDay={myCustomDay}
      renderTimelineEventContent={myCustomEvent}
      extendDefaultEvent={myDefaultEvent}
    />
  );
}

export default App;
```

### TSX

```tsx
import {
  Eventcalendar,
  formatDate,
  getJson,
  // MbscCalendarDayData,
  MbscCalendarEvent,
  MbscCalendarEventData,
  MbscEventcalendarView,
  MbscResource,
  setOptions,
} from '@mobiscroll/react';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';

setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

const App: FC = () => {
  const [myEvents, setEvents] = useState<MbscCalendarEvent[]>([]);

  const myView = useMemo<MbscEventcalendarView>(
    () => ({
      timeline: {
        type: 'week',
        startDay: 1,
        endDay: 5,
        startTime: '08:00',
        endTime: '20:00',
        resolutionHorizontal: 'hour',
        resolutionVertical: 'day',
      },
    }),
    [],
  );

  const myResources = useMemo<MbscResource[]>(
    () => [
      {
        id: 1,
        name: 'Green Hall',
      },
      {
        id: 2,
        name: 'White Hall',
      },
      {
        id: 3,
        name: 'Red Hall',
      },
      {
        id: 4,
        name: 'Blue Hall',
      },
      {
        id: 5,
        name: 'Yellow Hall',
      },
    ],
    [],
  );

  const myCustomDay = useCallback((day: { date: Date }) => {
    const date = day.date;
    return (
      <div className="md-timetable-day">
        <div className="md-timetable-day-name">{formatDate('DDDD', date)}</div>
        <div>{formatDate('MM/DD/YYY', date)}</div>
      </div>
    );
  }, []);

  const myCustomEvent = useCallback(
    (args: MbscCalendarEventData) => (
      <div>
        <div className="md-timetable-event-title">{args.title}</div>
        <div className="md-timetable-event-prop">Prof. {args.original!.prof}</div>
        <div className="md-timetable-event-class">{args.original!.class} year</div>
      </div>
    ),
    [],
  );

  const myDefaultEvent = useCallback(
    () => ({
      title: 'New class',
      prof: 'Stacia Jaden',
      class: 'Junior',
      color: '#ff0000',
    }),
    [],
  );

  useEffect(() => {
    getJson(
      'https://trial.mobiscroll.com/timetable-events/',
      (events: MbscCalendarEvent[]) => {
        setEvents(events);
      },
      'jsonp',
    );
  }, []);

  return (
    <Eventcalendar
      className="md-timetable"
      clickToCreate={true}
      dragToCreate={true}
      dragToMove={true}
      dragToResize={true}
      eventDelete={true}
      view={myView}
      data={myEvents}
      resources={myResources}
      renderTimelineDay={myCustomDay}
      renderTimelineEventContent={myCustomEvent}
      extendDefaultEvent={myDefaultEvent}
    />
  );
};

export default App;
```

### CSS

```css
.md-timetable .mbsc-timeline-row-date-col {
  width: 90px;
}

.md-timetable .mbsc-timeline-row-gutter {
  height: 8px;
}

.md-timetable .mbsc-timeline-column,
.md-timetable .mbsc-timeline-header-column {
  width: 130px;
}

.md-timetable .mbsc-schedule-event-range {
  display: none;
}

.md-timetable-day {
  font-size: 14px;
  padding: 7px;
}

.md-timetable-day-name {
  font-weight: 600;
  padding-bottom: 5px;
}

.md-timetable-event-title {
  font-size: 12px;
  line-height: 18px;
}

.md-timetable-event-prop {
  padding-bottom: 5px;
  opacity: 0.6;
}

.md-timetable-event-class {
  opacity: 0.6;
  font-style: italic;
}
```

## Implementation notes

- Use `type: 'week'` with `startDay: 1` and `endDay: 5` to limit the view to Monday through Friday.
- Set `startTime: '08:00'` and `endTime: '20:00'` to restrict the horizontal time axis to the relevant school hours.
- Set `resolutionHorizontal: 'hour'` so each column on the time axis represents one hour.
- Set `resolutionVertical: 'day'` to make the vertical axis repeat all resources under each day of the week, creating a timetable layout where rows represent classroom-per-day combinations rather than resources alone.
- Define resources as a flat list of classrooms. Each classroom row appears once under every day in the vertical axis.
- Use `renderTimelineDay` (Angular: `timelineDayTemplate`, Vue: `#timelineDay` slot) to render a custom day label with the full day name and the formatted date.
- Use `renderTimelineEventContent` (Angular: `timelineEventContentTemplate`, Vue: `#timelineEventContent` slot) to render a custom event body showing the class title, professor name, and student year level from custom event properties.
- Use `extendDefaultEvent` to pre-populate newly created events with a default title, professor, year level, and color.

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-react.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config react
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

On a trial, add `--trial` to the config command: `mobiscroll config react --trial`.

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/react/getting-started/installation

## Related demos

- Previous: [Dynamic Resource Availability](https://demo.mobiscroll.com/react/timeline/dynamically-color-and-invalidate.md) - Color-code resource rows and restrict drop zones by task type on a React Timeline — compatible resources turn green, incompatible ones gray during drag.
- Next: [Monthly Timetable View](https://demo.mobiscroll.com/react/timeline/monthly-timetable-vertical-days-horizontal-times.md) - Display a monthly timetable in the React Timeline — days listed vertically, hours across, with drag-to-create in a single-resource layout.
