Skip to content

Next.js and SSR

The bundle starts with "use client", so you can import ResourceScheduler from a server component. It still needs props that can be serialised across the boundary, and your handlers are functions, so keep them in a client component:

app/board/board.tsx
"use client";
import { useState } from "react";
import { ResourceScheduler } from "resource-scheduler";
import "resource-scheduler/dist/resource-scheduler.css";
export function Board({ initial }: { initial: Resource[] }) {
const [resources, setResources] = useState(initial);
return <ResourceScheduler resources={resources} /* handlers here */ />;
}

The functions that need no UI (isPlacementAllowed, findAvailableSlots, getUtilization, expandEvents, the layout, …) are also in resource-scheduler/headless, an entry without React or "use client" that you can call from a server component or a route handler. See Build your own UI.

Dates cross the server boundary as strings

Section titled “Dates cross the server boundary as strings”

A server component cannot pass Date objects to a client component the way you might expect: after JSON they arrive as strings. Convert them when you build state:

const revive = (rs: SerializedResource[]): Resource[] =>
rs.map((r) => ({
...r,
events: r.events.map((e) => ({ ...e, startDate: new Date(e.startDate), endDate: new Date(e.endDate) })),
}));

Slots and the “today” highlight depend on the current time, so a page rendered at one moment and hydrated at another can differ. Two ways to avoid a mismatch:

  • Pass initialDate explicitly (for example from the server) instead of relying on new Date().
  • Render the scheduler only on the client, for example with next/dynamic and ssr: false.

If you installed with the shadcn CLI, import from @/components/resource-scheduler and skip the stylesheet import. The copied files do not carry "use client" at the top of every file, so import the component from a client component.