Timelinx

Styling Components

CSS classes, data attributes, and customization patterns for all UI components

All @timelinx/ui components expose stable CSS class names and data-* attributes for styling. The class names are not scoped or hashed - they are stable public API.

Class Name Conventions

All components use a tl- prefix:

ClassComponent
.tl-editorTimelineEditor root
.tl-rulerTimelineRuler
.tl-trackTimelineTrack row
.tl-track-headerLeft header of a track row
.tl-clipTimelineClip
.tl-clip-labelClip name label
.tl-clip-thumbnailThumbnail strip inside a clip
.tl-playheadPlayhead line
.tl-toolbarTimelineToolbar
.tl-tool-btnIndividual tool button
.tl-snap-indicatorSnap indicator line
.tl-transportTransportControls
.tl-inspectorInspectorPanel

data-* Attributes

Components expose state as data-* attributes for CSS selectors and test selectors:

/* Style the active tool button */
.tl-tool-btn[data-active="true"] {
  background: var(--accent-subtle);
  color: var(--accent);
}

/* Style selected clips */
.tl-clip[data-selected="true"] {
  outline: 2px solid var(--selection);
  outline-offset: -1px;
}

/* Style disabled clips */
.tl-clip[data-enabled="false"] {
  opacity: 0.4;
}

/* Style locked tracks */
.tl-track[data-locked="true"] .tl-track-header {
  opacity: 0.6;
  cursor: not-allowed;
}

TimelineClip data attributes

AttributeValuesSet when
data-clip-idclip ID stringAlways
data-selected"true" / "false"In selection set
data-enabled"true" / "false"Clip is enabled/disabled
data-dragging"true" when absentDuring drag gesture
data-ghost"true" when absentProvisional drag preview
data-track-type"video" / "audio" / etc.Always

TimelineTrack data attributes

AttributeValuesSet when
data-track-idtrack ID stringAlways
data-track-type"video" / "audio" / "subtitle" / "title"Always
data-locked"true" / "false"Track is locked
data-muted"true" / "false"Track is muted
data-solo"true" / "false"Track is soloed

Targeting Specific Track Types

Use data-track-type to style track rows by type:

.tl-track[data-track-type="video"] {
  border-left: 2px solid var(--track-video);
}

.tl-track[data-track-type="audio"] {
  border-left: 2px solid var(--track-audio);
}

.tl-track[data-track-type="subtitle"] {
  border-left: 2px solid var(--track-subtitle);
}

Overriding Component Styles

Override styles after importing structure.css:

/* Increase clip corner radius */
.tl-clip {
  border-radius: var(--radius-sm);  /* 4px instead of default 2px */
}

/* Make the toolbar taller */
.tl-toolbar {
  height: 52px;
}

/* Increase font size in clip labels */
.tl-clip-label {
  font-size: var(--text-md);  /* 14px */
}

Use CSS variables over hardcoded values

Prefer var(--text-sm) over 12px. This ensures your customizations stay aligned with the design system and respond correctly to future token updates.


className Prop

All components accept a className prop for ad-hoc additions:

<TimelineTrack
  trackId="v1"
  className="my-highlighted-track"
/>
.my-highlighted-track {
  background: var(--accent-subtle);
}

style Prop

For inline overrides:

<TimelineClip
  clipId={clip.id}
  style={{ borderRadius: 6 }}
/>

CSS Layers

@timelinx/ui does not use @layer internally - all its styles are at the default layer. Your application-level styles in @layer utilities or @layer components will be overridden by structure.css.

If you're using Tailwind CSS layers, place @timelinx/ui imports outside any layer:

@import '@timelinx/ui/styles/presets/dark-pro';
@import '@timelinx/ui/styles/structure';

@layer utilities {
  /* Your Tailwind utilities here */
}

On this page