How to Build a School Class Schedule Calendar in JavaScript
By SimpleCalendarJS Team
Every school — from primary through university — needs a class schedule calendar. Students check which room to go to next, teachers see their daily load at a glance, and administrators assign classrooms without double-booking. The obvious path is licensing an enterprise scheduler component, but those start at $395/project and ship far more JavaScript than a timetable needs. A school class schedule calendar is simpler than it looks when you break it into parts.
What enterprise timetable components cost
Before writing code, understand the landscape. School scheduling tools fall into two categories: full SaaS platforms (Untis, aSc Timetables, Classter) and JavaScript UI components you embed in your own app. The SaaS route means per-school fees, zero customisation, and student data on someone else's servers. The component route gives you control — but the prices add up.
| Library | License Cost | Bundle Size | Timetable View | Framework Lock-in |
|---|---|---|---|---|
| Mobiscroll | $395+/project | ~80 KB+ | Timeline, scheduler | React/Vue/Angular/jQuery |
| DayPilot Pro | $649+ (1 dev, 1 app) | ~133 KB | Scheduler, timetable | React/Vue/Angular |
| MindFusion Scheduler | $749+ | ~90 KB+ | Timetable, resource | jQuery/React |
| DHTMLX Scheduler | $1,299+ (5 devs) | ~100 KB+ | Timeline, units | React/Vue/Angular |
| FullCalendar Premium | $480/dev/yr | ~200 KB | Resource timeline | React/Vue/Angular |
| SimpleCalendarJS | Free personal / $49/yr or $199 lifetime commercial | ~14 KB | Week, month, day | None — vanilla JS |
Mobiscroll has a dedicated multi-classroom timetable demo that renders rooms as rows with lessons as horizontal bars. It's the most school-specific option — but at $395+ per project, every school portal or internal tool needs its own license.
DayPilot Pro offers a scheduler view that works well for timetables, with drag-and-drop and event resizing. The minimum footprint is 133 KB gzipped for the scheduler component alone, and pricing starts at $649 for a single developer and single application.
FullCalendar is the default choice for calendar UIs, but its free core doesn't include resource views. Displaying rooms or teachers as rows requires the premium Scheduler plugin at $480/developer/year — a subscription, not a one-time purchase.
The pattern: enterprise schedulers charge enterprise prices for what is fundamentally a week grid with coloured blocks. If your school schedule doesn't need Gantt-chart-level resource management, you can build it with a lightweight calendar and own the result.
Building the school class schedule calendar
A school timetable has four core requirements: display classes in a weekly grid, colour-code by subject, assign rooms and teachers, and handle recurring weekly lessons. Here's how to build each one.
Step 1: Set up the calendar
npm install simple-calendar-js
import SimpleCalendarJs from 'simple-calendar-js'; import 'simple-calendar-js/dist/simple-calendar-js.min.css'; const timetable = new SimpleCalendarJs('#timetable', { defaultView: 'week', locale: 'en-US', enabledViews: ['week', 'day'], fetchEvents: async (start, end) => { const res = await fetch( `/api/classes?from=${start.toISOString()}&to=${end.toISOString()}` ); const classes = await res.json(); return classes.map((cls) => ({ id: cls.id, title: `${cls.subject} — ${cls.room}`, start: new Date(cls.startTime), end: new Date(cls.endTime), color: cls.subjectColor, })); }, onSlotClick: (date) => { openClassAssignmentModal(date); }, onEventClick: (event) => { openClassDetailModal(event); }, });
This renders a week-view timetable at ~14 KB gzipped with zero dependencies. Each class appears as a colour-coded block — maths in blue, science in green, English in amber. Clicking an empty slot opens the class creation form; clicking an existing class shows its details.
Step 2: Colour-code subjects
A timetable is useless if every class looks the same. Map subjects to colours so students and teachers can scan the week at a glance:
const SUBJECT_COLORS = { Mathematics: '#3b82f6', Science: '#22c55e', English: '#f59e0b', History: '#8b5cf6', 'Physical Education': '#ef4444', Art: '#ec4899', Music: '#06b6d4', }; function mapClassToEvent(cls) { return { id: cls.id, title: `${cls.subject}\n${cls.teacher} — ${cls.room}`, start: new Date(cls.startTime), end: new Date(cls.endTime), color: SUBJECT_COLORS[cls.subject] || '#6b7280', }; }
Step 3: Expand recurring weekly lessons
Most school timetables repeat the same pattern every week for an entire term. Instead of creating hundreds of individual events, define templates and expand them:
const classTemplates = [ { id: 'maths-9a-mon', subject: 'Mathematics', teacher: 'Ms. Chen', room: 'Room 201', dayOfWeek: 1, // Monday startTime: '09:00', endTime: '09:50', classGroup: '9A', color: '#3b82f6', }, { id: 'science-9a-mon', subject: 'Science', teacher: 'Mr. Okafor', room: 'Lab 3', dayOfWeek: 1, startTime: '10:00', endTime: '10:50', classGroup: '9A', color: '#22c55e', }, ]; function expandToEvents(templates, rangeStart, rangeEnd) { const events = []; const current = new Date(rangeStart); while (current <= rangeEnd) { const dayOfWeek = current.getDay(); templates.forEach((tpl) => { if (tpl.dayOfWeek === dayOfWeek) { const [startH, startM] = tpl.startTime.split(':').map(Number); const [endH, endM] = tpl.endTime.split(':').map(Number); const start = new Date(current); start.setHours(startH, startM, 0, 0); const end = new Date(current); end.setHours(endH, endM, 0, 0); events.push({ id: `${tpl.id}-${current.toISOString().split('T')[0]}`, title: `${tpl.subject}\n${tpl.teacher} — ${tpl.room}`, start, end, color: tpl.color, templateId: tpl.id, classGroup: tpl.classGroup, }); } }); current.setDate(current.getDate() + 1); } return events; }
On the server, store overrides — cancelled classes, substitute teachers, room changes — as exceptions linked to the template ID. When expanding, check for an override before emitting each occurrence.
Step 4: Prevent room double-booking
Two classes can't occupy the same room at the same time. Enforce this server-side:
async function createClass(pool, classData) { const { room, startTime, endTime, dayOfWeek, subject, teacher } = classData; const conflict = await pool.query( `SELECT id, subject, teacher FROM class_templates WHERE room = $1 AND day_of_week = $2 AND start_time < $3 AND end_time > $4`, [room, dayOfWeek, endTime, startTime] ); if (conflict.rows.length > 0) { const existing = conflict.rows[0]; return { status: 409, error: `${room} is already booked for ${existing.subject} with ${existing.teacher}`, }; } const result = await pool.query( `INSERT INTO class_templates (subject, teacher, room, day_of_week, start_time, end_time) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`, [subject, teacher, room, dayOfWeek, startTime, endTime] ); return { status: 201, classTemplate: result.rows[0] }; }
The overlap query uses the standard interval intersection check: two time ranges overlap if one starts before the other ends and ends after the other starts. Return a 409 Conflict with a descriptive message so the admin knows exactly which class is blocking the slot.
Filtering by class group, teacher, or room
A school timetable serves different audiences. Students want their class group's schedule. Teachers want their own. Administrators want a room-by-room view. Add filters without changing the calendar:
function filterEvents(events, filters) { return events.filter((event) => { if (filters.classGroup && event.classGroup !== filters.classGroup) { return false; } if (filters.teacher && !event.title.includes(filters.teacher)) { return false; } if (filters.room && !event.title.includes(filters.room)) { return false; } return true; }); } // Usage: show only Year 9A's timetable const filtered = filterEvents(allEvents, { classGroup: '9A' }); timetable.setEvents(filtered);
Build a dropdown above the calendar with class groups (9A, 9B, 10A …), a teacher picker, and a room picker. When the selection changes, re-filter and update the calendar. No round-trip to the server needed — filter the already-fetched data client-side.
Styling the timetable for school use
Customise SimpleCalendarJS with CSS custom properties to match your school's brand:
#timetable { --uc-primary: #1e40af; --uc-bg: #ffffff; --uc-border: #e5e7eb; --uc-text: #111827; } @media (prefers-color-scheme: dark) { #timetable { --uc-primary: #60a5fa; --uc-bg: #1f2937; --uc-border: #374151; --uc-text: #f9fafb; } }
Feature comparison: enterprise scheduler vs custom build
| Feature | Mobiscroll | DayPilot Pro | Custom + SimpleCalendarJS |
|---|---|---|---|
| Setup time | Hours | Hours | Half a day |
| Cost per school | $395+/project | $649+ | $49/yr or $199 lifetime |
| Bundle size | ~80 KB+ | ~133 KB | ~14 KB |
| Multi-room timeline | Built-in | Built-in | Custom (week grid + filters) |
| Recurring lessons | Built-in | Built-in | Your logic |
| Room conflict detection | Manual | Manual | Your logic (server-side) |
| Subject colour-coding | Config | Config | CSS + JS |
| Drag-and-drop rescheduling | Built-in | Built-in | Custom handler |
| Framework lock-in | React/Vue/Angular | React/Vue/Angular | None |
Enterprise schedulers win when you need a resource timeline view (rooms as rows, hours as columns) out of the box and your budget supports $395–$1,299+ per project. The custom build wins when you need a clean class schedule without the overhead — especially for school portals, internal admin tools, and applications where 14 KB matters more than a built-in Gantt chart.
Summary
- Enterprise timetable components (Mobiscroll, DayPilot, DHTMLX) cost $395–$1,299+ per project and ship 80–200 KB of JavaScript — more than most school schedules need
- A custom school schedule calendar built with SimpleCalendarJS ships at ~14 KB with full control over class templates, room assignments, and teacher filtering
- Recurring weekly lessons eliminate repetitive data entry — define each class once as a template with day, time, room, and teacher, then expand it across the entire term
- Room conflict detection must happen server-side — check for overlapping time ranges per room before inserting, and return a descriptive
409 Conflicterror - Colour-coding by subject (maths in blue, science in green, English in amber) gives students and teachers an instant visual overview of the week
- Client-side filtering by class group, teacher, or room lets one calendar serve every audience without extra server requests
Sources & Further Reading
Research & References
- Top JavaScript Scheduler Libraries in 2026 — jqwidgets.com
- Best React Scheduler Component Libraries — LogRocket Blog
- JavaScript Timeline Multi-Classroom Timetable Example — Mobiscroll
- MindFusion JavaScript Scheduler Samples — GitHub
- FullCalendar React Component — Docs
- DayPilot JavaScript Scheduler — Licensing and Pricing
- Compare the Best React Scheduler Components — DHTMLX Blog
- schedule-x/calendar — npm
Image Credits
- Cover: Students Sitting in the Classroom — Pexels
All images free to use under the Pexels License.
Frequently Asked Questions
What is the best JavaScript library for a school timetable?
It depends on complexity. Enterprise scheduler components like Mobiscroll ($395+/project) and DayPilot ($649+) offer built-in timeline and resource views. For a standard weekly class schedule — where you need a week grid with colour-coded subjects and click-to-edit — SimpleCalendarJS (~14 KB) handles the UI at a fraction of the cost. You keep full control of your timetable logic.
Can I build a school schedule calendar without React or Angular?
Yes. SimpleCalendarJS is a vanilla JavaScript library with zero framework dependencies. It works in plain HTML pages, WordPress themes, and any framework — React, Vue, Angular, Svelte. The scheduling logic (recurring lessons, room conflicts, teacher assignments) is standard JavaScript that runs anywhere.
How do I handle recurring classes that repeat every week?
Define a class template with the day of the week, start time, end time, subject, and room. On the server, expand templates into individual events for the requested date range. Store exceptions (cancellations, substitute teachers, room changes) as overrides linked to the template ID.
How do I prevent room double-booking in a school timetable?
Conflict detection must happen server-side. Before inserting a class, query the database for any existing classes that overlap the same time range in the same room. Use an atomic database operation (INSERT with WHERE NOT EXISTS or a unique constraint on room + time range) to prevent race conditions.
Is FullCalendar free for building a school schedule?
FullCalendar's core library is free and open source (MIT license), but it only covers basic calendar views. The Resource Timeline view — which displays rooms or teachers as rows with classes as blocks — requires the premium Scheduler plugin, starting at $480 per developer per year. A basic week view with FullCalendar core works but ships around 47 KB gzipped for the minimum viable setup.
How much does a school scheduling JavaScript component cost?
Enterprise JavaScript scheduler components range from $395/project (Mobiscroll) to $649+ (DayPilot) to $1,299+ for five developers (DHTMLX). MindFusion's scheduler starts at $749. Building your own with SimpleCalendarJS costs $49/year or $199 lifetime for commercial use, and is free for personal or open-source projects.
Add a calendar to your app today
Free for personal projects. $49/year or $199 lifetime per commercial project.
