Skip to content
SuperScheduler

Resource scheduling for Reactv0.1.0

Every resource.Every moment.Your product.

SuperScheduler is a React library for interactive resource planning: a fast, accessible timeline where your users drag, resize, zoom and undo, shaped around your business instead of the other way round.

  • React 18 and 19
  • TypeScript types included
  • No runtime dependencies
  • Lite on npm · Pro by private tarball
Framehouse
StagesStage A · CycloramaStage B · Kitchen setPost-productionEdit 1Edit 2Grading suiteMix stageCrewsCamera unit 1Camera unit 2Spring campaign · Offline editHarbor documentary · Offline editSpring campaign · GradeKitchen spot · GradeSpring campaign · MixKitchen spot · ShootKitchen spot · ShootFacility · Rigging maintenanceKitchen spot · Crew callKitchen spot · Crew callKitchen spot · Offline editHarbor documentary · ShootHarbor documentary · Crew callTuesday, October 13Wednesday, October 14Thursday, October 15Friday, October 168 AM12 PM4 PM8 AM12 PM4 PM8 AM12 PM4 PM8 AM12 PM4 PM

Loads SuperScheduler Pro only when you ask for it.

One engine, your vocabulary

What are you organizing?

The same surface, three businesses. Resources, time scale, labels and actions change with the job; the engine underneath stays the same.

Open the agency example
DesignInés G.Marc D.Yuki T.CopyLena F.Omar S.MotionSara N.Teo R.Brand systemLaunch key visualLaunch layoutsRetail kitRetail moodboardIcon setLaunch scriptLaunch copyRetail claimsLaunch filmLogo animationRetail loopsOct 12Oct 1912 Mon13 Tue14 Wed15 Thu16 Fri17 Sat18 Sun19 Mon20 Tue21 Wed22 Thu23 Fri24 Sat25 Sun

Loads SuperScheduler Pro only when you ask for it.

Explore time

From the quarter to the quarter hour.

Zoom continuously with a pinch, Ctrl/⌘ and the wheel, or the buttons below. Headers, labels and detail adapt as the scale changes, and the minimap keeps the whole season in view.

  1. 01One time-per-pixel scale: zooming never re-renders React.
  2. 02Zoom levels you define, each with its own headers.
  3. 03The minimap draws whatever load your application computes.
Jump to a scaleQuarter · Month · Week · Day · Hours · 15 min
North hallHall AHall BHall CSouth pavilionStudio 1Studio 2TerraceSetupExhibitionRegistrationKeynoteCoffee breakPanelLunchPanelSetupExhibitionSetupExhibitionConferenceSetupExhibitionSetupExhibitionWorkshopSetupExhibitionConferenceSetupExhibitionConferenceConferenceConferenceConferenceWorkshopConferenceConferenceBreakoutBreakoutWorkshopConferenceWorkshopConferenceConferenceConferenceConferenceWorkshopConferenceWorkshopConferenceBreakoutBreakoutBreakoutConferenceConferenceConferenceWorkshopConferenceWorkshopWorkshopConferenceSetupExhibitionConferenceWorkshopSetupExhibitionWorkshopSetupConferenceConferenceConferenceWorkshopConferenceConferenceLunchWorkshopConferenceConferenceConferenceConferenceOct 1Oct 5Oct 12Oct 19Oct 26Nov 21234567891011121314151617181920212223242526272829303112345

Loads SuperScheduler Pro only when you ask for it.

Pinch or Ctrl/⌘ + scroll over the timeline to zoom around the pointer.

Group byTeam
BrandAna P.DesignJonas K.MotionMei L.DesignRafa D.ProductionProductNoor H.EngineeringLuca B.EngineeringIris V.DesignTom S.ProductionStudioEva M.MotionKofi A.MotionLia R.DesignMax W.EngineeringAtlas relaunchNimbus campaignAtlas relaunchAtlas relaunchHarbor appNimbus campaignHarbor appNimbus campaignAtlas relaunchHarbor appNimbus campaignNimbus campaignHarbor appAtlas relaunchNimbus campaignAtlas relaunchHarbor appNimbus campaignAtlas relaunchHarbor appHarbor appNimbus campaignAtlas relaunchHarbor appAtlas relaunchNimbus campaignHarbor appOct 12Oct 19Oct 2612131415161718192021222324252627282930311

Loads SuperScheduler Pro only when you ask for it.

Work with resources

Teams, rooms and machines, arranged the way you think about them.

Resources can be a flat list, a tree several levels deep or a table with columns. Regroup the same people by team or by skill, filter as you type, and keep the timeline aligned.

  1. 1Tree rowsParents fold and unfold; children keep their own events.
  2. 2Row header columnsResizable columns read from your resource data.
  3. 3FiltersRows and events filter through callbacks you write.

Act with confidence

Move it. Read the callback. Undo it.

Every gesture reaches your code as a typed callback while it happens and after it lands. Refuse a move with a reason, confirm it with your server, or let it through. History is one import away.

Closed for acoustic maintenance: Studio 4
Studio 1Studio 2Studio 3Studio 4Studio 5Studio 6Night FerryCopper BloomLumen ChoirNight FerryHalcyonCopper BloomLumen ChoirHalcyonStatic OrchardStatic OrchardHalcyonOct 12Oct 1912 Mon13 Tue14 Wed15 Thu16 Fri17 Sat18 Sun19 Mon20 Tue21 Wed22 Thu23 Fri24 Sat25 Sun

Loads SuperScheduler Pro only when you ask for it.

  1. 1Drag a booking to another room or day.
  2. 2Try to drop one on the room under maintenance.
  3. 3Press Undo, or Ctrl/⌘ + Z inside the board.
Handler: act-handlers.ts
act-handlers.tsts
/**
 * Booking-board handlers of the "act with confidence" demo. This file is shown on the page as
 * the code that runs: the library proposes, these handlers decide, React state persists.
 */
import { type SuperScheduler } from 'super-scheduler'
import type { SchedulerProps } from 'super-scheduler'
import { hitsMaintenance } from '../data/bookings'
import type { CallbackRecord } from '../callback-log'

type Log = (record: Omit<CallbackRecord, 'seq'>) => void

export function createBookingHandlers(log: Log, refusal: string): Partial<SchedulerProps> {
  return {
    // Visual and enforced: the library refuses drops on disabled cells.
    onBeforeCellRender: (args) => {
      const { resource, start, end } = args.cell
      if (hitsMaintenance(String(resource), start.value, end.value))
        args.cell.properties.disabled = true
    },

    // While dragging: explain the refusal next to the pointer.
    onEventMoving: (args) => {
      if (hitsMaintenance(String(args.resource), args.start.value, args.end.value)) {
        args.allowed = false
        args.message = refusal
      }
    },

    // Before the commit: the last word, e.g. after asking a server.
    onEventMove: (args) => {
      const refused = hitsMaintenance(
        String(args.newResource),
        args.newStart.value,
        args.newEnd.value,
      )
      if (refused) args.preventDefault()
      log({
        name: 'onEventMove',
        args: {
          'e.id()': String(args.e.id()),
          'e.text()': args.e.text(),
          newResource: String(args.newResource),
          newStart: args.newStart.value,
          newEnd: args.newEnd.value,
        },
        ...(refused ? { refused: refusal } : {}),
      })
    },

    onEventMoved: (args) =>
      log({
        name: 'onEventMoved',
        args: {
          'e.id()': String(args.e.id()),
          newResource: String(args.newResource),
          newStart: args.newStart.value,
          newEnd: args.newEnd.value,
        },
      }),

    onEventResized: (args) =>
      log({
        name: 'onEventResized',
        args: {
          'e.id()': String(args.e.id()),
          what: args.what,
          newStart: args.newStart.value,
          newEnd: args.newEnd.value,
        },
      }),
  }
}

export function isBookingEvent(
  event: SuperScheduler.EventData,
): event is SuperScheduler.EventData<{ client: string }> {
  return 'client' in event && typeof event.client === 'string'
}

It fits your product

Your data and your rules, on a timeline you don’t have to build.

A component, typed props and callbacks. The library owns rendering, gestures, virtualization and accessibility; your application owns data, validation and persistence.

SuperScheduler
Renders resources and events, virtualized in both directions.
Your application
Supplies the data and decides the time window.
src/Planning.tsxtsx
import { SuperSchedulerComponent } from 'super-scheduler'
import type { SuperScheduler } from 'super-scheduler'
import 'super-scheduler/styles.css'

const rooms: SuperScheduler.ResourceData[] = [
  { id: 'studio-a', name: 'Studio A' },
  { id: 'studio-b', name: 'Studio B' },
]

const bookings: SuperScheduler.EventData[] = [
  {
    id: 'shoot-01',
    resource: 'studio-a',
    text: 'Product shoot',
    start: '2026-10-02',
    end: '2026-10-04',
  },
  {
    id: 'edit-01',
    resource: 'studio-b',
    text: 'Edit',
    start: '2026-10-04T09:00:00',
    end: '2026-10-04T17:00:00',
  },
]

export function Planning() {
  return (
    <div style={{ height: 480 }}>
      <SuperSchedulerComponent
        startDate="2026-10-01"
        days={14}
        scale="Day"
        cellWidth={56}
        timeHeaders={[{ groupBy: 'Month' }, { groupBy: 'Day', format: 'd' }]}
        height="100%"
        resources={rooms}
        events={bookings}
      />
    </div>
  )
}

Dress it like your product

Real tokens, real contrast, copy the CSS.

These controls change the --super-scheduler-* custom properties the library reads. The contrast check uses WCAG 2 ratios; the CSS below is what you paste into your stylesheet.

Accent
Surface
Event radius7 px
Event style
Density
Preview
Event text contrast8.5:1Passes AA for normal text
Studio 1Studio 2Studio 3Studio 4Studio 5Night FerryCopper BloomLumen ChoirNight FerryHalcyonCopper BloomLumen ChoirHalcyonStatic OrchardOct 12Oct 1912 Mon13 Tue14 Wed15 Thu16 Fri17 Sat18 Sun19 Mon20 Tue21 Wed

Loads SuperScheduler Pro only when you ask for it.

Your theme.css
/* SuperScheduler theme (light). Put the class on the element that wraps the scheduler, */
/* and pass density="comfortable" to SuperSchedulerComponent. */
.my-planning {
  --super-scheduler-accent-rgb: 25 97 68;
  --super-scheduler-surface: #fcfaf6;
  --super-scheduler-surface-raised: #f6f3ee;
  --super-scheduler-text: #161b22;
  --super-scheduler-text-muted: #4a5058;
  --super-scheduler-border: #ddd8d2;
  --super-scheduler-row-line: #ddd8d2;
  --super-scheduler-grid-line: #e9e6e0;
  --super-scheduler-selection: rgb(25 97 68 / 0.12);
  --super-scheduler-selection-border: rgb(25 97 68 / 0.75);
  --super-scheduler-focus-ring: rgb(25 97 68 / 0.5);
  --super-scheduler-today-bg: rgb(25 97 68 / 0.06);
  --super-scheduler-weekend-bg: rgb(0 0 0 / 0.025);
  --super-scheduler-hover-cell: rgb(25 97 68 / 0.06);
  --super-scheduler-hover-row: rgb(25 97 68 / 0.03);
  --super-scheduler-event-radius: 7px;
  --super-scheduler-event-bg: #dee6df;
  --super-scheduler-event-border: #b3c9bd;
  --super-scheduler-event-text: #124631;
  --super-scheduler-event-bar: #196144;
}

Examples

Every example has its own data model, rules, mission and source code. Six to start with:

See all twelve examples

Lite and Pro

Start with a read-only timeline. Grow into a planning product.

Both editions share the data model, the civil-date handling, virtualization and keyboard support. Pro adds everything that changes the plan.

Lite

Free on npm

For availability boards, occupancy views and read-only planning screens.

  • Daily timeline of flat resources
  • Events with colors and overlap stacking
  • Click callbacks for events and cells
  • Keyboard navigation and 2-D virtualization
  • No limit on resources or events

npm install super-scheduler-lite

Pro

€499 per year

For products where people move, resize and decide on the timeline itself.

  • Drag, resize, validation and conflict feedback
  • Hours, minutes and continuous zoom
  • Resource trees, columns, frozen and split rows
  • Dependencies, multiselection, undo and redo
  • Minimap, panes, saved views, range loading, React slots

Private, versioned tarball over HTTPS

Compare the editions in detail

Before you decide

Questions teams ask before adopting it

Is it a React component or a framework-agnostic engine?

Both. SuperSchedulerComponent is the React wrapper for React 18 and 19; underneath, a DOM engine handles scrolling, zoom and gestures without React renders. You can also mount it imperatively with new SuperScheduler.Scheduler(element, options).

React integration →
How good are the TypeScript types?

Declarations ship with the package. Options, callbacks and control methods are typed, and event data is generic: EventData<YourFields> keeps your own fields typed in handlers and render hooks.

Resources, events and intervals →
Can it look like the rest of our product?

Yes. Colors, radius, density and dark mode come from documented CSS custom properties; classNames and styles reach individual parts; React render slots replace the content of events, rows and headers.

Theming guide →
Who stores the data, and who prevents conflicts?

Your application. The scheduler shows and edits what you give it and reports every change through callbacks. Persistence, permissions and the final word on conflicts belong to your backend; the library helps with overlap prevention, blocked cells and refusals with a reason.

Controlled events and callbacks →
How is Pro distributed?

As a private, versioned .tgz over HTTPS that npm installs like any URL dependency. The download key appears in your manifest and lockfile, so treat it as a secret. Lite is a regular public npm package.

Install Pro →
Can users work with the keyboard and screen readers?

Pro has a full keyboard mode: arrows move focus, Enter activates, Alt+arrows move events, and changes are announced to assistive technology in English, Spanish, French, German and five more languages. Lite supports keyboard navigation too.

Keyboard and accessibility →
Does it handle hours and minutes, or only days?

Pro covers months down to 5-minute cells, hides nights or weekends when you ask it to, and switches scale continuously. Lite is a daily timeline.

Hours, minutes, days and zoom →
What about time zones and recurring events?

Dates are civil wall-clock values, deliberately free of time zones. Convert zoned instants and expand recurrences in your application before handing events to the scheduler.

Languages, dates and time zones →