Installation

Install the schedule with its two peers and hand it plain data: lanes, tasks, subtasks and dependencies. It draws them and reports what a planner wants to change.

import { useSchedule } from "@umriss-ui/schedule";
npm install @umriss-ui/schedule @umriss-ui/core @umriss-ui/charts

The command brings its two peers along: core for the formats and the wording, charts for the time scale and the operating calendar (ADR-0022). React 19 or newer is a peer as well and stays the application's own. The stylesheets load themselves - each package's script imports its own, so there is nothing to import by hand; @umriss-ui/schedule/styles.css stays exported for setups that link stylesheets themselves.

The plan is plain data (ADR-0023). A lane is a person, a vehicle or a room, declared in JSX by its id. A task is an id, a colour and a name; a subtask is a main time on one lane, belonging to a task, with an optional lead-in and lead-out; a dependency joins two subtasks of one task with a lag. Times are epoch milliseconds.

The schedule reports, the application decides. It draws the data it is given and changes none of it: a drag ends in an intent reported to onIntent, and only the application's own state update moves a bar. Without intents the schedule is read-only - see Move and lane.

Examples

The smallest schedule

Two people, one project, one dependency: lanes in JSX, the rest as plain arrays handed to Subtasks and Dependencies.

import { useSchedule } from "@umriss-ui/schedule";
import type { Dependency, Subtask, Task } from "@umriss-ui/schedule";

const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
const min = (n: number) => n * 60_000;

const tasks: Task[] = [{ id: "portal", name: "Member portal", color: "light-dark(#7c3aed, #a98bfa)" }];

const subtasks: Subtask[] = [
  { id: "design", task: "portal", lane: "noah", from: at(9), to: at(11), leadOut: min(15) },
  { id: "build", task: "portal", lane: "arjun", from: at(12), to: at(15, 30), leadIn: min(30) },
];

const dependencies: Dependency[] = [{ id: "handover", from: "design", to: "build", lag: min(15) }];

export default function SmallestSchedule() {
  const { Schedule, Lane, Subtasks, Dependencies } = useSchedule({ initialView: { domain: [at(8), at(16)] } });
  return (
    <Schedule ariaLabel="Tuesday, design and build" height={150}>
      <Lane id="noah" label="Noah Fischer" />
      <Lane id="arjun" label="Arjun Mehta" />
      <Dependencies data={dependencies} />
      <Subtasks data={subtasks} tasks={tasks} />
    </Schedule>
  );
}

Keyboard

The keys of First schedule apply here.

Props on this page

From ScheduleProps — the full table stands on First schedule.

NameTypeDefaultDescription
heightnumber400Height in CSS pixels, both bands included. The width is the host's.
childrenReactNode—Lane, Dependencies and Subtasks, in the order they are to stand and be drawn.

Accessibility

NameTypeDefaultDescription
ariaLabelrequiredstring—What the schedule shows, for a screen reader: "Plan of week 38".

From LaneProps — the full table stands on Lanes.

NameTypeDefaultDescription
idrequiredstring—The identity subtasks name in their lane.
labelReactNodeidWhat the lane header says - the person, vehicle or room. Real text, read by a screen reader.

From SubtasksProps — the full table stands on Subtasks.

NameTypeDefaultDescription
datarequiredreadonly Subtask[]—The subtasks, as the caller holds them. The schedule never changes one.
tasksrequiredreadonly Task[]—The tasks the subtasks belong to - their identity and their colour. A subtask whose task is not among them is drawn in a muted colour.

From Subtask — the full table stands on Subtasks.

NameTypeDefaultDescription
idrequiredstring—The caller's identity of the subtask.
taskrequiredstring—The id of the task it belongs to.
lanerequiredstring—The id of the lane it sits on.
fromrequirednumber—Start of the main time.
torequirednumber—End of the main time.
leadInnumber—Duration of the lead-in before the main time; none is zero.
leadOutnumber—Duration of the lead-out after the main time; none is zero.

From Task — the full table stands on Subtasks.

NameTypeDefaultDescription
idrequiredstring—The caller's identity of the task.
colorrequiredstring—Any CSS colour - a literal, a token, light-dark(…). The colour means what the caller's domain needs it to mean.
namestring—What the task is called, where the schedule names it.

From DependenciesProps — the full table stands on Dependencies.

NameTypeDefaultDescription
datarequiredreadonly Dependency[]—The dependencies, as the caller holds them.

From Dependency — the full table stands on Dependencies.

NameTypeDefaultDescription
idrequiredstring—The caller's identity of the dependency.
fromrequiredstring—The id of the subtask it leaves.
torequiredstring—The id of the subtask it arrives at.
lagrequirednumber—The least time between the two anchors; zero where the successor may begin as soon as the predecessor ends.

From ScheduleOptions — the full table stands on View.

NameTypeDefaultDescription
initialViewScheduleView—The view to start from, read once when the hook first runs; a different value on a later render is ignored, as React ignores a changed defaultValue. To go to a view later, call setView. The schedule remembers none: where a view is kept is the application's decision.

From ScheduleView — the full table stands on View.

NameTypeDefaultDescription
domainreadonly [number, number]—The span in view, as two wall-clock instants. Absent, the schedule shows the extent of its subtasks, within zoomLimits.

Every page of @umriss-ui/schedule

Getting started

Plan

Time

Reading

Editing

Measuring

API index