Documentation

React editor hooks

Bind your custom UI to engine state with domain-specific React hooks and accessible primitives.

Browse documentation

The React package exposes hooks for binding product chrome, interaction layers, media monitors, and accessible controls to a shared TimelineEngine. This page explains how to choose timeline hooks imported from @techsquidtv/canvas-timeline-react/hooks; the maintained catalog lives in the React registry Hook groups, with category-grouped API references on each timeline hook group page. Primitive hooks from other React subpaths, such as useRangeScrollbar() from @techsquidtv/canvas-timeline-react/range-scrollbar, are documented with their own primitive registry entries.

The four visible hook groups are curated task groups. The API rows inside those groups are populated from the docs app’s hook metadata, and the registry verifier checks that metadata against the public @techsquidtv/canvas-timeline-react/hooks export barrel. Internal helper hooks are intentionally excluded until they are exported as public APIs.

Use the timeline hook registry groups as the source of truth:

  • Timeline State: engine context, state snapshots, active clips/layers, viewport data, ruler ticks, clip geometry, and visible clip queries.
  • Editing Hooks: edit mode, typed edit commands, shared edit previews, range selection, clip, clip group, track, marker, selection, clipboard, history, track header, edit consequences, existing-clip drag/drop, and app-owned media drops onto the timeline.
  • Playback Controls: transport state, live playhead time, snapping, media synchronization, and clip playback effects.
  • Accessible Controls: Base UI-compatible sliders, viewport scrollbar adapters, pan/zoom controls, and constant-DOM clip navigation.

Start with the narrowest hook that matches the component. Toolbar buttons that mutate timeline structure should use command hooks such as useTimelineEditCommands(); toolbar state can compose snapshot hooks such as useTimelinePlayback() or useTimelineClips(). Readouts that must follow scrubbing or playback should use focused live hooks such as useTimelinePlayheadTime(), useActiveMarkers(), or useTimelineClipDropFeedback(). Use useTimeline() directly only when a component needs both the shared engine and the synchronized state snapshot.

Mutating hook commands return TimelineCommandResult, so custom controls can branch on ok and machine-readable failure reasons without reading private engine state.

Custom ruler surfaces

Use useTimelineRulerTicks() when rendering ruler ticks with DOM, SVG, or a custom drawing system. It consumes the same core geometry as CanvasRenderer and subscribes only to viewport changes. Choose the display with the explicit format discriminant:

const ticks = useTimelineRulerTicks({
format: 'timecode',
frameRate: { numerator: 30000, denominator: 1001 },
minimumMajorTickSpacing: 96,
});

Use { format: 'seconds' } for elapsed clock labels or { format: 'frame-number', frameRate } for absolute frame numbers. Frame-aware rulers derive their major intervals from the project rate and return major, medium, and minor visual weights. DOM renderers should set minimumMajorTickSpacing from their typography and handle label alignment at the viewport edges; the canvas renderer performs both measurements automatically.

The React DOM timeline demo provides a live format selector and renders all three modes from this hook.

Edit command hooks

Use useTimelineEditCommands() for product chrome and custom gestures that need to validate, preview, commit, or cancel timeline edits. The hook calls TimelineEngine command APIs; the engine resolves snapping, ripple, overwrite, split, range, history, and event consequences.

Compose the focused hooks around it:

  • useTimelineEditMode() stores the selected tool or edit intent for toolbar chrome without mutating engine state.
  • useTimelineEditPreview() subscribes to command preview validity and command state.
  • useTimelineEditImpacts() subscribes to affected-clip consequences for live guides, renderer overlays, and drag-time affordances.
  • useTimelineRangeSelection() adapts In/Out points to delete-range and lift-range commands.
  • useTimelineClipGroups() reads timeline clip groups and exposes group, ungroup, and selected-group commands for editor chrome.
import { fromSeconds } from '@techsquidtv/canvas-timeline-utils';
import {
useTimelineClips,
useTimelineEditCommands,
useTimelineEditImpacts,
useTimelineEditMode,
useTimelineEditPreview,
useTimelineRangeSelection,
} from '@techsquidtv/canvas-timeline-react/hooks';
function EditToolbar() {
const { selectedClip } = useTimelineClips();
const { mode, setMode } = useTimelineEditMode();
const editCommands = useTimelineEditCommands();
const editPreview = useTimelineEditPreview();
const editImpacts = useTimelineEditImpacts();
const rangeSelection = useTimelineRangeSelection();
return (
<>
<button aria-pressed={mode === 'trim'} onClick={() => setMode('trim')}>
Trim
</button>
<button
disabled={!selectedClip}
onClick={() =>
selectedClip &&
editCommands.moveClip({
clipId: selectedClip.id,
startTime: fromSeconds(4),
})
}
>
Move
</button>
<button disabled={!rangeSelection.hasRange} onClick={() => rangeSelection.liftRange()}>
Lift
</button>
{editPreview.previewing && <span>{editImpacts.impacts.length} affected</span>}
</>
);
}

Accessibility and keyboard composition

Canvas Timeline keeps repeated clips and track visuals on canvas for performance, while low-count interaction chrome stays in DOM. The hook layer is the bridge between those two surfaces.

Use control adapters when composing semantic UI:

  • useTimelinePlayheadControl(), useTimelineInOutRangeControl(), useTimelineZoomControl(), and useTimelinePanControl() return Base UI-compatible props and formatted value text.
  • useTimelineViewportScrollbar() and useTimelineViewportRangeControl() adapt viewport state to generic range scrollbar primitives.
  • useTimelineVerticalScrollbar() and useTimelineVerticalRangeControl() adapt track-stack scroll state to the same primitives.
  • useTimelineClipNavigation() exposes one active canvas clip at a time instead of requiring one DOM node per clip.
  • useTimelineKeyboard() returns focus-scoped keyboard shortcut props for opt-in editor transport, mark, marker, snapping, and zoom commands.
  • useTimelineTrack() and useTimelineTrackHeader() expose one track’s first-party state, canvas-aligned row geometry, and DOM-ready header props for custom track header compositions.
  • useTimelineKeyframes(), useTimelineKeyframeDrag(), useTimelineKeyframeSegments(), and useTimelineKeyframeTangentDrag() expose headless keyframe geometry, tangent handles, commands, property evaluation, and drag previews for custom keyframe editors.

Control adapter onValueCommitted callbacks receive the committed value plus opaque TimelineControlCommitDetails forwarded from the underlying control primitive. Canvas Timeline settles the engine before forwarding that metadata, but does not inspect it; narrow the details in application code when a specific control library documents extra fields.

Keyboard behavior from these hooks is opt-in and scoped to the element that spreads the returned props. Canvas Timeline does not install global hotkeys or override application shortcuts.

For shadcn-like composition, wrap the interactive editor region instead of registering document-level listeners:

<Timeline.KeyboardScope frameRate={24}>
<Timeline.Root>
<Timeline.ClipInteractionLayer />
<Timeline.PlayheadArea />
<Timeline.PlayheadGrabber />
</Timeline.Root>
</Timeline.KeyboardScope>

Pass bindings when your product owns a different shortcut map. Custom bindings replace the preset so applications can avoid collisions with their own command system. Frame-step shortcuts are included only when frameRate is supplied. Use platform when tests, server rendering, or product settings need deterministic platform-specific preset bindings.