# Migrating from Lite to Pro

> Move an integration from super-scheduler-lite to super-scheduler: what stays the same, which defaults and callbacks change, and how to adopt Pro features step by step.

Source: https://superscheduler.org/en/docs/migrate-lite-to-pro/
Reviewed: 2026-10-07

Install the Pro tarball as `super-scheduler`, change the imports and the stylesheet from `super-scheduler-lite` to `super-scheduler`, and write out Lite's defaults, because Pro's defaults differ (one day of hourly cells, editing on, keyboard off). The component name, ISO date strings, resource and event fields and the basic options carry over. Replace Lite's `onTimeRangeClick` with `onTimeRangeSelected`, then enable Pro features one at a time.

Lite and Pro share their component name, their civil date model and their basic data shapes, so a Lite view moves to Pro with a handful of edits. The differences that matter are the defaults, a few callbacks and the styling tokens. This guide converts a Lite view to an equivalent read-only Pro view first, then adds Pro features one by one, so each step can be tested on its own.

## What stays the same
| Area | Shared by Lite and Pro |
|---|---|
| Component | `SuperSchedulerComponent`, with `ref.current.control` and `controlRef` |
| Dates | Civil ISO strings with seconds, half-open intervals, `SuperScheduler.Date` and `SchedulerDate` with the same methods |
| Resources | `{ id, name }`, ids compared strictly (`1` and `'1'` differ) |
| Events | `id`, `resource`, `start`, `end`, `text`, `backColor`, `fontColor`, `cssClass`, `toolTip`, `tags` |
| Options | `startDate`, `days`, `scale: 'Day'`, `cellWidth`, `height`, `rowHeaderWidth`, `rowMinHeight`, `eventHeight`, `locale`, `emptyState` |
| Control | `update()`, `scrollTo()`, `scrollToResource()`, `visibleStart()`, `visibleEnd()`, `dispose()`, `disposed()` |
| Callback | `onEventClick({ e })` with `e.data` |

Everything Lite accepts has a Pro counterpart except `ariaLabel` (see below). Pro options such as `treeEnabled` or `zoomLevels`, which Lite rejects with "unsupported option", work once you switch.

## Switch the package
Pro is installed from a versioned HTTPS tarball under the package name `super-scheduler`. Remove Lite unless another part of your app still uses it:

```sh
npm uninstall super-scheduler-lite
npm install https://npm.superscheduler.org/pro/YOUR_DOWNLOAD_KEY/0.1.0.tgz
```

`package.json` then lists the URL and your lockfile records its integrity. The key in that URL is a download secret: it appears in `package.json` and the lockfile, so treat both accordingly. [Install SuperScheduler Pro](https://superscheduler.org/en/docs/install-pro/) covers keys, CI and upgrades. Pro lists React and React DOM (18.2 or later, or 19) as peer dependencies.

## Update imports, styles and defaults
Here is a Lite view:

```tsx
// src/Availability.tsx (Lite)
import { useState } from 'react'
import { SuperSchedulerComponent } from 'super-scheduler-lite'
import type { SuperScheduler } from 'super-scheduler-lite'
import 'super-scheduler-lite/styles.css'

const ROOMS: SuperScheduler.ResourceData[] = [
  { id: 'r101', name: 'Room 101' },
  { id: 'r102', name: 'Room 102' },
]
const EVENTS: SuperScheduler.EventData[] = [
  {
    id: 'b-1042',
    resource: 'r101',
    start: '2026-10-02T14:00:00',
    end: '2026-10-05T11:00:00',
    text: 'Ana Ruiz',
    backColor: '#dbeafe',
  },
  {
    id: 'b-1043',
    resource: 'r102',
    start: '2026-10-03T14:00:00',
    end: '2026-10-08T11:00:00',
    text: 'Tom Berg',
    backColor: '#dcfce7',
  },
]

/** Before: the read-only Lite view. */
export function Availability() {
  const [picked, setPicked] = useState('')
  return (
    <>
      <p aria-live="polite">{picked}</p>
      <SuperSchedulerComponent
        startDate="2026-10-01"
        resources={ROOMS}
        events={EVENTS}
        ariaLabel="Room availability"
        onEventClick={({ e }) => setPicked(`Booking ${String(e.data.id)}`)}
        onTimeRangeClick={({ start, resource }) =>
          setPicked(`Free: ${String(resource)} on ${start.toString('d MMM')}`)
        }
      />
    </>
  )
}
```
And the same view on Pro:

```tsx
// src/Availability.tsx (Pro)
import { useCallback, useState } from 'react'
import { SuperSchedulerComponent } from 'super-scheduler'
import type {
  SchedulerEventClickArgs,
  SchedulerTimeRangeSelectedArgs,
  SuperScheduler,
} from 'super-scheduler'
import 'super-scheduler/styles.css'

const ROOMS: SuperScheduler.ResourceData[] = [
  { id: 'r101', name: 'Room 101' },
  { id: 'r102', name: 'Room 102' },
]
const EVENTS: SuperScheduler.EventData[] = [
  {
    id: 'b-1042',
    resource: 'r101',
    start: '2026-10-02T14:00:00',
    end: '2026-10-05T11:00:00',
    text: 'Ana Ruiz',
    backColor: '#dbeafe',
  },
  {
    id: 'b-1043',
    resource: 'r102',
    start: '2026-10-03T14:00:00',
    end: '2026-10-08T11:00:00',
    text: 'Tom Berg',
    backColor: '#dcfce7',
  },
]
// Lite draws one header row with "d MMM" per day.
const TIME_HEADERS: SuperScheduler.TimeHeaderData[] = [{ groupBy: 'Day', format: 'd MMM' }]

/** After: the same view on Pro, still read-only. */
export function Availability() {
  const [picked, setPicked] = useState('')
  // Pro splices the events array it receives: give it its own copy.
  const [events] = useState(() => EVENTS.slice())

  const onEventClick = useCallback((args: SchedulerEventClickArgs) => {
    setPicked(`Booking ${String(args.e.id())}`)
  }, [])

  // Lite's onTimeRangeClick fires for any empty cell. In Pro, clicking an empty cell selects it;
  // Pro's own onTimeRangeClick fires only for a click on a range that is already selected.
  const onTimeRangeSelected = useCallback((args: SchedulerTimeRangeSelectedArgs) => {
    args.control.clearSelection()
    if (args.origin !== 'click' && args.origin !== 'keyboard') return
    setPicked(`Free: ${String(args.resource)} on ${args.start.toString('d MMM')}`)
  }, [])

  return (
    // Pro has no ariaLabel option: name the region around it.
    <section aria-label="Room availability">
      <p aria-live="polite">{picked}</p>
      <SuperSchedulerComponent
        // Lite's defaults, written out: Pro's defaults differ.
        startDate="2026-10-01"
        days={31}
        scale="Day"
        cellWidth={64}
        heightSpec="Fixed"
        height={400}
        rowHeaderWidth={160}
        rowHeaderWidthAutoFit={false}
        rowMinHeight={40}
        eventHeight={26}
        timeHeaders={TIME_HEADERS}
        emptyState="No resources"
        // Read-only, as in Lite: Pro enables dragging, resizing and zoom gestures by default.
        eventMoveHandling="Disabled"
        eventResizeHandling="Disabled"
        zoomGesture={false}
        // Keyboard navigation is built into Lite and opt-in in Pro.
        keyboardEnabled
        keyboardTarget="component"
        keyboardMode="Full"
        resources={ROOMS}
        events={events}
        onEventClick={onEventClick}
        onTimeRangeSelected={onTimeRangeSelected}
      />
    </section>
  )
}
```
You should see the same rooms, bookings and colors, the same messages on click, and no dragging. The grid uses your page's font instead of Lite's 13 px system font, and Pro's theme colors.

The edits, in order:

1. Imports: `super-scheduler-lite` becomes `super-scheduler`, and `super-scheduler-lite/styles.css` becomes `super-scheduler/styles.css`.
2. Defaults: write out every Lite default you relied on (table below).
3. Behavior: disable what Pro turns on by default, enable keyboard support.
4. Callbacks: move cell clicks to `onTimeRangeSelected`.
5. Data: give the control its own copy of the events array, because Pro splices the array it receives when events change. Lite treats its arrays as read-only.

| Option | Lite default | Pro default |
|---|---|---|
| `days` | `31` | `1` |
| `scale` | `'Day'` (the only value) | `'CellDuration'` with `cellDuration: 60`, hourly cells |
| `cellWidth` | `64` | `40` |
| `height` | `400`, fixed | `600`, a maximum (`heightSpec: 'Max'`): the grid shrinks to its rows |
| `rowHeaderWidth` | `160` | `80`, and `rowHeaderWidthAutoFit: true` grows it to the names |
| `rowMinHeight` | `40` | `0` |
| `eventHeight` | `26` | `35` |
| `emptyState` | `'No resources'` | none |
| `ariaLabel` | `'Resource schedule'` | not available |
| Time header | one row, `d MMM` | `[{ groupBy: 'Default' }, { groupBy: 'Cell' }]` |

Pro has no `ariaLabel` option: its grid has a built-in accessible name. Put the label on the region that contains it, as the example does with `<section aria-label>`.

### Styles and selectors
Class names and tokens change prefix. Lite's root is `.super-scheduler-lite` with parts such as `.super-scheduler-lite__event`; Pro's root is `.super-scheduler` with `.super-scheduler__event`, plus `[data-super-scheduler-part]` markers. Map Lite's six tokens as a starting point:

| Lite token | Pro token |
|---|---|
| `--super-scheduler-background` | `--super-scheduler-surface` |
| `--super-scheduler-text` | `--super-scheduler-text` |
| `--super-scheduler-border` | `--super-scheduler-border` |
| `--super-scheduler-header` | no single equivalent; style the `timeHeader` slot or `.super-scheduler__header` |
| `--super-scheduler-event` | `--super-scheduler-event-bg` (or `backColor` per event) |
| `--super-scheduler-focus` | `--super-scheduler-focus-color` and `--super-scheduler-focus-ring` |

Pro has a richer token set, dark mode and density presets; see [Theming](https://superscheduler.org/en/docs/theming/).

## Behavior that Pro turns on
Lite is read-only by construction. Pro is an editor, so out of the box it:

- moves and resizes events by dragging (`eventMoveHandling` and `eventResizeHandling` default to `'Update'`);
- selects time ranges on click and drag (`timeRangeSelectedHandling: 'Enabled'`), leaving the selection shadow until the next selection, a click elsewhere or `clearSelection()`;
- zooms with Ctrl or Cmd plus the wheel and with pinch gestures (`zoomGesture: true`);
- leaves keyboard support off (`keyboardEnabled: false`), while Lite always has arrow-key navigation. With `keyboardEnabled` Pro listens on the whole document unless `keyboardTarget` is `'component'`.

The Pro example above pins all of these to Lite's behavior. Remove those lines one at a time as you adopt features.

## Callbacks with richer arguments
| Lite | Pro |
|---|---|
| `onEventClick({ control, e: { data }, originalEvent })` | `onEventClick({ e, div, control, originalEvent, ctrl, shift, meta, preventDefault })`, where `e` is a `SuperScheduler.Event` with `data`, `id()`, `start()`, `end()`, `text()`, `resource()` and `duration()`; then `onEventClicked` |
| `onTimeRangeClick({ control, start, end, resource, originalEvent })` on any empty cell | `onTimeRangeSelected({ start, end, resource, control, origin, multirange })`, with `origin` `'click'`, `'drag'`, `'keyboard'` or `'api'` |

> **Behavior:**
> Pro also has an `onTimeRangeClick`, but it means something else: it fires when the user clicks a time range that is already selected. A click on an empty cell in Pro is a one-cell selection reported by `onTimeRangeSelect` (before, cancelable) and `onTimeRangeSelected` (after). Filter on `args.origin === 'click'` if drags must not count.

Other differences to check in your handlers:

- In Pro, handlers run with `this` set to the control, and most arguments include `control`.
- In Lite, `originalEvent` is a `KeyboardEvent` when a cell or event is activated from the keyboard. In Pro, Enter on an event dispatches a click, so `onEventClick` always receives a `MouseEvent`, and Enter on a cell is a selection with `origin: 'keyboard'`.
- `controlRef` callbacks are called with `null` on unmount in Lite; Pro calls them only with the control and clears ref objects on unmount.
- `scrollTo(date)` takes optional `animated` and `position` arguments in Pro.

## When both packages are installed
Some products keep Lite on public pages and use Pro in the back office. That works, with two rules:

- **Exchange ISO strings, not date objects.** Each edition has its own date class, and Pro rejects a Lite date object.
- **Keep their CSS apart.** Each package has its own stylesheet. Some token names exist in both (`--super-scheduler-text`, `--super-scheduler-border`), so scope Lite overrides to `.super-scheduler-lite` instead of `:root`.

```ts
// src/dates.ts
import { type SuperScheduler as Lite } from 'super-scheduler-lite'
import { SuperScheduler as Pro } from 'super-scheduler'

// Each edition has its own date class. Passing a Lite date object to Pro throws
// ("expected a Date, a SchedulerDate, a number of ticks or an ISO 8601 string").
export function toProDate(date: Lite.Date): Pro.Date {
  return new Pro.Date(date.value)
}

// Shared state, URLs and storage hold civil ISO strings, which both editions accept.
export const selectedDay: string = Pro.Date.today().value
```
Import the two components under different local names when one module needs both, for example `import { SuperSchedulerComponent as LiteScheduler } from 'super-scheduler-lite'`.

## Adopt Pro features step by step
Once the read-only view matches, add one capability at a time and test it:

1. **Keyboard and accessibility.** Keep `keyboardEnabled` and `keyboardMode="Full"`; see [Keyboard, accessibility and touch](https://superscheduler.org/en/docs/keyboard-accessibility-touch/).
2. **Editing.** Remove `eventMoveHandling="Disabled"` and `eventResizeHandling="Disabled"`, add rules with `onEventMoving` and `onEventMove`, and persist changes from `onEventsChange`; see [Drag and resize rules](https://superscheduler.org/en/docs/drag-resize-rules/) and [Controlled state](https://superscheduler.org/en/docs/controlled-state/).
3. **Creating bookings.** Use `onTimeRangeSelected` with `origin === 'drag'` to open a form.
4. **Hours and zoom.** Add `zoomLevels`, remove `zoomGesture={false}`; see [Time scales and zoom](https://superscheduler.org/en/docs/time-scales-zoom/).
5. **Rows.** Trees, frozen rows, split rows and row header columns; see [Trees, columns and selection](https://superscheduler.org/en/docs/trees-columns-selection/).
6. **Modules.** [Undo and redo](https://superscheduler.org/en/docs/undo-redo/), [Minimap](https://superscheduler.org/en/docs/minimap-metrics/), [Links](https://superscheduler.org/en/docs/links-dependencies/), [Panes and saved views](https://superscheduler.org/en/docs/panes-saved-views/) and [Range loading](https://superscheduler.org/en/docs/range-loading/).
7. **React content.** Switch the import to `super-scheduler/react-render` when you need React inside events or headers; see [React render slots](https://superscheduler.org/en/docs/react-render-slots/).

→ https://superscheduler.org/en/examples/hotel-rooms/
For commercial questions about Pro, see the [pricing page](https://superscheduler.org/en/pricing/).
