Styling model
Canvas Timeline keeps high-density visuals on the canvas renderer so scroll, zoom, and playback stay fast. CSS still controls the lower-count DOM pieces around that canvas.
| Surface | Styled by | Examples |
|---|---|---|
| Canvas visuals | Renderer theme | Clip fills, clip labels, track lanes, ruler ticks, markers, snap lines. |
| Interaction layers | Library CSS | Scrollbar parts, playhead grabbers, In/Out grabbers, active clip handles. |
| Track headers | Library CSS | Optional DOM track header rows, state styling, and resize handles. |
| Timeline shell utilities | Library CSS | Optional timeline shell, stage, scrollbar row, and control utility classes. |
| Product and page chrome | Application CSS | Page layout, media previews, inspectors, menus, panels, dialogs. |
| Timeline data color | Timeline state | clip.color values used for category or media-specific clip colors. |
This split keeps the editor performance model intact: CSS can follow your app theme, but clips, tracks, rulers, markers, and similarly dense visuals do not become hundreds of DOM nodes.
Timeline.ClipInteractionLayer follows the same boundary. It renders one
hovered, selected, or actively edited clip affordance and uses pointer capture
for the active edit. CSS variables can style that one affordance, but repeated
clip bodies, labels, and selected borders remain canvas-painted.
For advanced customization of the canvas drawing pipeline (including overrides, custom canvas layers, and theme/metrics configuration), see the Canvas renderer customization guide.
Stylesheet entrypoints
Canvas Timeline follows shadcn’s ownership model: your app defines semantic tokens, and package components consume them. Because this is a packaged component library rather than copied source, the components also need a small mechanics stylesheet for layout, hit targets, pointer behavior, canvas sizing, grabbers, scrollbars, intrinsic affordance shapes, and accessibility helpers.
For the clearest shadcn-like split, import the mechanical layer and the token-consuming style layer explicitly:
import '@techsquidtv/canvas-timeline/base.css';import '@techsquidtv/canvas-timeline/theme.css';base.css contains required geometry, stacking, pointer behavior, hit-area
rules, and intrinsic affordance shapes only. It is not a visual theme: it does
not set colors, borders, shadows, typography, focus treatment, or theme radii.
Import it by itself only when your app provides every visual rule for the DOM
chrome:
import '@techsquidtv/canvas-timeline/base.css';theme.css contains shadcn-token-driven visual treatment for package-owned DOM
interaction chrome, optional timeline shell/control utility classes, and the
timeline variables that the canvas renderer resolves. It consumes app-owned
tokens such as --background, --foreground, --border, --input, and
--ring; it does not define those app theme tokens for you.
styles.css is only the bundled import of those two package layers:
import '@techsquidtv/canvas-timeline/styles.css';CSS variables
theme.css expects tokens such as --background, --foreground, --border,
--input, --ring, --primary, --muted, --muted-foreground, --accent,
--destructive, --radius, --font-sans, and --font-mono.
Apps that do not use shadcn should define the same semantic tokens before using
theme.css, or set explicit --timeline-* variables on a timeline or
standalone primitive container after importing the package stylesheet.
The default timeline tokens map to shadcn semantics. Override --timeline-*
tokens on a timeline container when you want a local timeline-specific treatment
without changing the rest of your app’s shadcn theme.
Use app semantic tokens such as --background, --foreground, --border,
--primary, and --ring for product chrome, panels, dialogs, media previews,
and page or demo layout. Use --timeline-* tokens for exported Canvas Timeline
primitives and renderer visuals. Use app-local or demo-local tokens for custom
composition details that are not part of the timeline package contract.
Surface Tokens
| Timeline token | Default mapping | Used for |
|---|---|---|
--timeline-panel |
var(--background) |
Timeline shell and canvas panel surface. |
--timeline-panel-muted |
var(--muted) |
Muted timeline areas such as ruler chrome. |
--timeline-panel-control |
var(--input) |
Control and input surfaces. |
--timeline-panel-control-hover |
var(--accent) |
Hovered control surfaces and default clips. |
--timeline-border |
var(--border) |
Timeline structural borders. |
--timeline-border-width |
2px |
Timeline shell and structural border width. |
--timeline-canvas-background |
var(--timeline-panel) |
Canvas stage background. |
--timeline-radius-sm |
calc(var(--radius) - 0.125rem) |
Small controls and clip corners. |
--timeline-radius-md |
calc(var(--radius) - 0.25rem) |
Timeline shell radius. |
--timeline-radius-full |
9999px |
Pills, knobs, and round controls. |
--timeline-shadow-sm |
Mix of --foreground and transparency |
Small raised DOM affordance shadow. |
Ruler And Tracks
| Timeline token | Default mapping | Used for |
|---|---|---|
--timeline-ruler-background |
var(--timeline-panel-muted) |
Canvas and DOM ruler surface. |
--timeline-ruler-tick |
var(--muted-foreground) |
Ruler tick marks. |
--timeline-ruler-text |
var(--muted-foreground) |
Ruler labels. |
--timeline-track-divider |
Mix of --timeline-border and transparency |
Track separators. |
--timeline-track-divider-width |
1px |
Track separator thickness. |
--timeline-track-locked-overlay |
Mix of --foreground and transparency |
Canvas overlay for locked tracks. |
--timeline-track-header-background |
var(--timeline-panel-muted) |
DOM track header column. |
--timeline-track-header-background-selected |
var(--timeline-panel-control-hover) |
Selected DOM track headers. |
--timeline-track-header-foreground |
var(--foreground) |
Active DOM track header text. |
--timeline-track-header-muted-foreground |
var(--muted-foreground) |
Muted, locked, or inactive header text. |
--timeline-track-header-border |
var(--timeline-track-divider) |
DOM track header dividers. |
--timeline-track-header-resize-handle-hover |
var(--timeline-clip-focus-ring) |
Hovered/focused resize handle. |
--timeline-font-ruler |
10px var(--font-mono) |
Canvas ruler labels. |
--timeline-font-clip |
12px var(--font-sans) |
Canvas clip labels. |
Clips And Markers
| Timeline token | Default mapping | Used for |
|---|---|---|
--timeline-marker |
var(--timeline-ruler-text) |
Markers without a data-defined color. |
--timeline-marker-text |
var(--timeline-ruler-text) |
Marker labels. |
--timeline-clip-background |
var(--timeline-panel-control-hover) |
Default canvas clip fill. |
--timeline-clip-background-selected |
Mix of --foreground and --timeline-panel |
Selected canvas clip fill. |
--timeline-clip-border |
transparent |
Default canvas clip border. |
--timeline-clip-border-selected |
transparent |
Selected canvas clip border. |
--timeline-clip-radius |
var(--timeline-radius-sm) |
Default canvas clip corner radius. |
--timeline-clip-inset-y |
0px |
Default canvas clip vertical inset. |
--timeline-clip-label-padding-x |
8px |
Default canvas clip label padding. |
--timeline-clip-text |
var(--foreground) |
Default canvas clip label text. |
--timeline-clip-text-selected |
var(--foreground) |
Selected canvas clip label text. |
--timeline-clip-handle-background |
Mix of --foreground and transparency |
Inactive active-clip trim handles. |
--timeline-clip-handle-active-background |
Mix of --foreground and transparency |
Active active-clip trim handles. |
--timeline-clip-handle-opacity |
0.85 |
Inactive active-clip handle opacity. |
--timeline-clip-handle-active-opacity |
1 |
Active active-clip handle opacity. |
--timeline-clip-feedback-background |
Mix of --foreground and transparency |
Active clip feedback overlay. |
--timeline-clip-feedback-border |
var(--timeline-border) |
Active clip feedback border. |
--timeline-clip-focus-ring |
var(--primary) |
Clip, timecode, and control focus treatment. |
--timeline-keyframe-line |
Mix of --foreground and transparency |
Canvas keyframe value curve. |
--timeline-keyframe-fill |
var(--timeline-panel) |
Default keyframe handle fill. |
--timeline-keyframe-fill-selected |
var(--timeline-clip-focus-ring) |
Selected keyframe handle fill. |
--timeline-keyframe-stroke |
var(--foreground) |
Default keyframe handle stroke. |
--timeline-keyframe-stroke-selected |
var(--timeline-clip-focus-ring) |
Selected keyframe handle stroke. |
Playhead, In/Out, And Snap Feedback
| Timeline token | Default mapping | Used for |
|---|---|---|
--timeline-playhead |
var(--primary) |
DOM playhead line and handle. |
--timeline-playhead-width |
1px |
DOM playhead line width. |
--timeline-playhead-hover |
var(--primary) |
Hovered or dragged playhead color. |
--timeline-playhead-hover-background |
Mix of --primary and transparency |
Playhead grabber hover hit-area fill. |
--timeline-playhead-shadow |
0 0 6px var(--timeline-playhead) |
Playhead hover and drag glow. |
--timeline-inout-accent |
var(--ring) |
Shared In/Out range color source. |
--timeline-inout-area |
Mix of --timeline-inout-accent and transparency |
Canvas In/Out range fill and DOM-only range indicator. |
--timeline-inout-border |
var(--timeline-inout-accent) |
DOM In/Out grabbers and opt-in canvas boundary lines. |
--timeline-inout-hover |
Mix of --timeline-inout-accent and transparency |
In/Out grabber hover hit-area fill. |
--timeline-inout-hover-border |
var(--timeline-inout-accent) |
Hovered or dragged In/Out grabber color. |
--timeline-inout-hover-shadow |
none |
In/Out hover shadow. |
--timeline-inout-active-shadow |
none |
In/Out drag/active shadow. |
--timeline-snap-line |
var(--ring) |
Canvas snap feedback line. |
--timeline-drop-target |
Mix of --timeline-inout-accent and transparency |
Valid cross-track clip drop target lane fill. |
--timeline-drop-target-invalid |
Mix of --destructive and transparency |
Invalid cross-track clip drop target lane fill. |
--timeline-drop-target-border |
Mix of --timeline-inout-accent and transparency |
Active cross-track clip drop target lane border. |
Scrollbars
| Timeline token | Default mapping | Used for |
|---|---|---|
--timeline-scrollbar-bg |
var(--timeline-panel) |
Scrollbar track background. |
--timeline-scrollbar-border |
var(--timeline-border) |
Scrollbar border. |
--timeline-scrollbar-thumb |
var(--muted-foreground) |
Scrollbar thumb. |
--timeline-scrollbar-thumb-hover |
var(--foreground) |
Hovered or dragged thumb. |
--timeline-scrollbar-handle-grip |
Mix of --background and transparency |
Scrollbar handle grip dot. |
--timeline-scrollbar-handle-grip-hover |
var(--background) |
Hovered scrollbar grip dot. |
Controls
| Timeline token | Default mapping | Used for |
|---|---|---|
--timeline-control-foreground |
var(--muted-foreground) |
Control labels, buttons, and values. |
--timeline-control-hover-border |
var(--foreground) |
Hovered control button borders. |
--timeline-control-hover-foreground |
var(--accent-foreground) |
Hovered control button text. |
--timeline-control-active-background |
var(--foreground) |
Active control button fill and border. |
--timeline-control-active-foreground |
var(--background) |
Active control button text. |
--timeline-control-slider-thumb |
var(--foreground) |
Control slider thumb fill. |
Inputs And Timecode Fields
| Timeline token | Default mapping | Used for |
|---|---|---|
--timeline-input-font-family |
var(--font-mono) |
Timecode input and field text. |
--timeline-input-border |
var(--timeline-border) |
Timecode/input border. |
--timeline-input-background |
var(--timeline-panel-control) |
Timecode/input background. |
--timeline-input-foreground |
var(--foreground) |
Timecode/input text. |
--timeline-input-placeholder |
var(--muted-foreground) |
Timecode/input placeholder text. |
--timeline-input-focus-border |
var(--timeline-clip-focus-ring) |
Focused input border. |
--timeline-input-focus-ring |
Mix of --timeline-clip-focus-ring and transparency |
Focused input ring. |
--timeline-input-invalid-border |
var(--destructive) |
Invalid input border. |
--timeline-input-invalid-ring |
Mix of --destructive and transparency |
Invalid input focus ring. |
--timeline-input-focus-shadow |
0 0 0 3px var(--timeline-input-focus-ring) |
Focused input shadow. |
--timeline-input-invalid-shadow |
0 0 0 3px var(--timeline-input-invalid-ring) |
Invalid input focus shadow. |
Nested theme scoping
Define shadcn semantic tokens at your app boundary. Canvas Timeline components read those tokens from the nearest scope, so the same import follows normal shadcn dark-mode scoping:
.dark { --background: oklch(0.17352 0 0); --foreground: oklch(0.985 0 0); --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); --border: oklch(1 0 0 / 12%); --input: oklch(1 0 0 / 15%); --ring: oklch(0.75 0.18 85); --primary: oklch(0.75 0.18 85); --primary-foreground: oklch(0.145 0 0); --muted: oklch(0.2024 0 0); --muted-foreground: oklch(0.708 0 0); --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); --radius: 0.625rem; --font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;}Set timeline tokens on the package root or a selector that targets package roots after importing package CSS only when you need a local component-specific override:
.editor-theme .timeline-root,.editor-theme .timecode-input { --timeline-marker: var(--muted-foreground); --timeline-clip-border-selected: var(--foreground); --timeline-playhead: var(--primary); --timeline-inout-accent: oklch(0.62 0.16 250);}