Skip to content

ReferenceSliders

TimeSlider.Markers

Draws a marker on the time slider for each cue on the text tracks a filter matches, such as ad breaks

A part of the time slider that draws a marker for each cue on the text tracks a filter matches, such as ad breaks, quiz questions, or highlights. Its props, data attributes, and custom properties are listed with the time slider’s other parts.

Import

import { TimeSlider } from '@videojs/react';

Anatomy

<TimeSlider.Root>
  <TimeSlider.Track>
    <TimeSlider.Fill />
  </TimeSlider.Track>
  <TimeSlider.Markers filter={{ label: 'ads' }} />
  <TimeSlider.Thumb />
</TimeSlider.Root>

renderMarker renders each marker, and defaults to a <div>. It receives the marker’s attributes and its state. Spread the attributes on the marker’s root element: they carry the slider’s data attributes, the marker’s data-active and data-point attributes, and a style that sets its --media-slider-marker-* custom properties.

<TimeSlider.Markers
  filter={{ label: 'ads' }}
  renderMarker={(props, state) => <div {...props} className="ad-marker" title={state.cue.text} />}
/>

The state is a TimeSliderMarkerState, exported from @videojs/react:

Field Type Description
cue MediaTextCue The cue the marker draws.
key string Stable identity of the marker.
index number Position among the drawn markers, from 0.
start, end number Marker bounds, in seconds, clamped to the slider. end equals start for a point.
point boolean Whether the cue marks one moment rather than a span.
active boolean Whether the cue is active now.
startPercent, endPercent `${number}%` Marker bounds as a percentage of the slider.
width, height `${number}%` | undefined Marker size along the slider’s orientation, 0% for a point; the other is undefined.
orientation 'horizontal' | 'vertical' The slider’s orientation.

Behavior

filter picks the tracks whose cues are drawn, by kind, label, or language, or with a function. A track definition works too. Keep a function filter’s identity across renders.

Tracks from the media and from the app are drawn alike. While the markers are rendered, the text cues feature reads the tracks they match, so tracks it skips by default work too.

A cue whose end is its start is a point, drawn as a marker with no width and data-point. Any other cue is a range, spanning from its start to its end and clamped to the slider. Markers sit on the same span as the slider: from 0 to the media’s duration, or to the end of its seekable range while the duration is unknown. Cues outside that span, and every cue while it’s unknown, aren’t drawn. Markers are ordered by start, then end.

Styling

Attribute Description
data-active Present while the marker’s cue is active.
data-point Present when the cue marks one moment rather than a span.

Each marker also carries the slider’s data attributes, such as data-orientation, and its geometry through:

  • --media-slider-marker-start
  • --media-slider-marker-end
  • --media-slider-marker-width, the marker’s size along the slider, 0% for a point

Markers are unstyled. Position each one from its custom properties, and give points a visible width:

.ad-marker {
  position: absolute;
  inset-block: 0;
  left: var(--media-slider-marker-start);
  width: var(--media-slider-marker-width);
  min-width: 4px;
}

.ad-marker[data-active] {
  background: orange;
}

Accessibility

The markers render with aria-hidden="true"; the slider’s value is what assistive technology reads. When a marker carries meaning a viewer needs, such as an upcoming ad break, convey it another way too.

Examples

Basic usage

An app track labeled ads holds a point at 8 seconds and a range from 18 to 24 seconds. A marker turns orange while its cue is active.

import { Container, type TextCueInit, TimeSlider, useCreateTextTrack } from '@videojs/react';
import { Video, VideoPlayer } from '@videojs/react/video';

const ads: TextCueInit[] = [{ startTime: 8 }, { startTime: 18, endTime: 24 }];

function AdsTrack() {
  useCreateTextTrack({ kind: 'metadata', label: 'ads', cues: ads });

  return null;
}

export default function BasicUsage() {
  return (
    <VideoPlayer>
      <Container className="react-time-slider-markers-basic__container">
        <Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoPlay muted playsInline loop />
        <AdsTrack />
        <TimeSlider.Root className="react-time-slider-markers-basic__slider">
          <TimeSlider.Track className="react-time-slider-markers-basic__track">
            <TimeSlider.Fill className="react-time-slider-markers-basic__fill" />
          </TimeSlider.Track>
          <TimeSlider.Markers
            filter={{ label: 'ads' }}
            className="react-time-slider-markers-basic__markers"
            renderMarker={(props) => <div {...props} className="react-time-slider-markers-basic__marker" />}
          />
          <TimeSlider.Thumb className="react-time-slider-markers-basic__thumb" />
        </TimeSlider.Root>
      </Container>
    </VideoPlayer>
  );
}