TourKit
@tour-kit/mediaComponents

NativeVideo

NativeVideo component: self-hosted HTML5 video with captions, poster images, responsive sources, and picture-in-picture

Overview

NativeVideo provides a powerful wrapper around the HTML5 <video> element with built-in support for captions, responsive sources, reduced motion, and accessibility features. Perfect for self-hosted videos where you need full control.

Why Use NativeVideo?

  • Full control: Host your own content, no third-party dependencies
  • Privacy: No external tracking or cookies
  • Captions: Built-in support for WebVTT subtitles
  • Responsive: Serve different videos based on screen size
  • Accessibility: Focus management, keyboard controls, reduced motion
  • Formats: MP4, WebM, OGG support with fallbacks

Basic Usage

import { NativeVideo } from '@tour-kit/media'

export function TutorialVideo() {
  return (
    <NativeVideo
      src="/videos/tutorial.mp4"
      alt="Feature tutorial walkthrough"
      poster="/thumbnails/tutorial.jpg"
      controls
    />
  )
}

Props

Prop

Type

Examples

Basic Video with Controls

<NativeVideo
  src="/videos/demo.mp4"
  alt="Product demonstration"
  poster="/thumbnails/demo.jpg"
  controls
/>

Auto-playing Background Video

<NativeVideo
  src="/videos/hero-background.mp4"
  alt="Platform overview background video"
  autoplay
  muted
  loop
  controls={false}
  playsInline
/>

Video with Captions

Provide accessibility for hearing-impaired users:

<NativeVideo
  src="/videos/tutorial.mp4"
  alt="Account setup tutorial"
  poster="/thumbnails/tutorial.jpg"
  captions={[
    {
      src: '/captions/en.vtt',
      srcLang: 'en',
      label: 'English',
      default: true
    },
    {
      src: '/captions/es.vtt',
      srcLang: 'es',
      label: 'Español'
    },
    {
      src: '/captions/fr.vtt',
      srcLang: 'fr',
      label: 'Français'
    }
  ]}
  controls
/>

Responsive Video Sources

Serve optimized videos based on viewport size:

<NativeVideo
  src="/videos/demo-1080p.mp4" // Fallback
  alt="Feature demonstration"
  poster="/thumbnails/demo.jpg"
  sources={[
    { src: '/videos/demo-480p.mp4', maxWidth: 640 },
    { src: '/videos/demo-720p.mp4', maxWidth: 1024 },
    { src: '/videos/demo-1080p.mp4', maxWidth: Infinity }
  ]}
  controls
/>

The component automatically selects the appropriate video based on screen width.

Multiple Format Fallbacks

Serve different formats for browser compatibility:

<NativeVideo
  src="/videos/demo.mp4" // Fallback for all browsers
  alt="Product demo"
  sources={[
    { src: '/videos/demo.webm', type: 'video/webm' }, // Modern browsers
    { src: '/videos/demo.mp4', type: 'video/mp4' },   // Broad support
    { src: '/videos/demo.ogv', type: 'video/ogg' }    // Firefox fallback
  ]}
  controls
/>

Reduced Motion Fallback

Show static image for users who prefer reduced motion:

<NativeVideo
  src="/videos/animated-feature.mp4"
  alt="Animated feature showcase"
  poster="/images/feature-static.jpg"
  reducedMotionFallback="/images/feature-static.jpg"
  autoplay
  loop
  muted
/>

When prefers-reduced-motion: reduce is detected, the static image displays instead.

Preload Strategies

Control bandwidth usage with preload settings:

// Don't preload - save bandwidth
<NativeVideo
  src="/videos/optional-demo.mp4"
  alt="Optional feature demo"
  preload="none"
  controls
/>

// Preload metadata only - shows duration and poster
<NativeVideo
  src="/videos/tutorial.mp4"
  alt="Tutorial video"
  preload="metadata"
  controls
/>

// Preload entire video - instant playback
<NativeVideo
  src="/videos/intro.mp4"
  alt="Welcome video"
  preload="auto"
  autoplay
  muted
/>

Event Handlers for Analytics

Track video engagement:

import { useState } from 'react'

function AnalyticsExample() {
  const [played, setPlayed] = useState(false)
  const [completed, setCompleted] = useState(false)

  return (
    <NativeVideo
      src="/videos/demo.mp4"
      alt="Product demo"
      onPlay={() => {
        if (!played) {
          setPlayed(true)
          analytics.track('Video Started', { video: 'demo' })
        }
      }}
      onEnded={() => {
        setCompleted(true)
        analytics.track('Video Completed', { video: 'demo' })
      }}
      controls
    />
  )
}

Caption Tracks

The CaptionTrack interface for the captions prop:

interface CaptionTrack {
  src: string          // URL to WebVTT file
  srcLang: string      // BCP 47 language code (e.g., 'en', 'es', 'fr')
  label: string        // Display name in captions menu
  kind?: 'subtitles' | 'captions' | 'descriptions'
  default?: boolean    // Set as default track
}

Creating WebVTT Files

WebVTT (Web Video Text Tracks) format for captions:

WEBVTT

00:00:00.000 --> 00:00:03.000
Welcome to the tutorial.

00:00:03.500 --> 00:00:07.000
Let's start by creating a new project.

00:00:07.500 --> 00:00:11.000
Click the "New Project" button in the top right.

Save as .vtt file and reference in captions prop.

Responsive Sources

The ResponsiveSource interface:

interface ResponsiveSource {
  src: string          // Video file URL
  maxWidth?: number    // Maximum viewport width for this source
  type?: string        // MIME type (e.g., 'video/mp4', 'video/webm')
}

Selection Logic

Sources are selected based on current viewport width:

sources={[
  { src: 'mobile.mp4', maxWidth: 640 },    // Used when width ≤ 640px
  { src: 'tablet.mp4', maxWidth: 1024 },   // Used when 641px ≤ width ≤ 1024px
  { src: 'desktop.mp4', maxWidth: Infinity } // Used when width > 1024px
]}

The component automatically updates when viewport size changes.

Video Formats

Recommended formats for broad compatibility:

MP4 (H.264)

  • Best for: Universal compatibility
  • Codec: H.264 video, AAC audio
  • Browsers: All modern browsers
  • File size: Medium to large

WebM (VP9)

  • Best for: Modern browsers, smaller files
  • Codec: VP9 video, Opus audio
  • Browsers: Chrome, Firefox, Edge
  • File size: Smaller than MP4

OGG (Theora)

  • Best for: Firefox fallback
  • Codec: Theora video, Vorbis audio
  • Browsers: Firefox, older browsers
  • File size: Varies

Recommended approach: Provide WebM and MP4, let browser choose best format.

Accessibility

Required Alt Text

Always provide descriptive alt text:

// Good - describes what's shown
<NativeVideo
  src="setup.mp4"
  alt="Step-by-step walkthrough of initial account setup"
/>

// Bad - too vague
<NativeVideo
  src="setup.mp4"
  alt="Video"
/>

Captions Are Essential

Provide captions for all videos with speech:

<NativeVideo
  src="tutorial.mp4"
  alt="Feature tutorial"
  captions={[
    { src: 'captions-en.vtt', srcLang: 'en', label: 'English', default: true }
  ]}
/>

WCAG 2.1 AA requires captions for prerecorded video content.

Keyboard Controls

Native video controls are fully keyboard accessible:

  • Space - Play/Pause
  • Tab - Navigate controls
  • Enter - Activate button
  • Arrow keys - Volume and seek (in some browsers)

Focus Management

The component manages focus for screen reader users:

  • Announces video state changes
  • Properly labels all interactive controls
  • Respects prefers-reduced-motion

Performance Optimization

Lazy Loading

Load videos only when needed:

<NativeVideo
  src="large-video.mp4"
  alt="Demo video"
  preload="none" // Don't load until user clicks play
  poster="thumbnail.jpg"
/>

Poster Images

Always provide poster images to reduce initial load:

<NativeVideo
  src="demo.mp4"
  alt="Demo"
  poster="demo-poster.jpg" // Shows while loading
  preload="metadata"
/>

Compression

Optimize video files before hosting:

  • Use H.264 with appropriate bitrate (2-5 Mbps for 1080p)
  • Compress audio to 128-192 kbps AAC
  • Consider adaptive bitrate streaming for long videos

Integration with Tours

Embed videos in onboarding steps:

import { Tour, TourStep } from '@tour-kit/react'
import { NativeVideo } from '@tour-kit/media'

<Tour id="video-tour">
  <TourStep id="welcome">
    <h2>Welcome to Our Platform</h2>
    <NativeVideo
      src="/videos/intro.mp4"
      alt="Platform introduction and overview"
      poster="/thumbnails/intro.jpg"
      captions={[
        { src: '/captions/intro-en.vtt', srcLang: 'en', label: 'English', default: true }
      ]}
      autoplay
      muted
      controls
    />
  </TourStep>
</Tour>

TypeScript

Full type safety with intelligent prop validation:

import type { NativeVideoProps, CaptionTrack } from '@tour-kit/media'

const captions: CaptionTrack[] = [
  { src: '/captions/en.vtt', srcLang: 'en', label: 'English', default: true },
  { src: '/captions/es.vtt', srcLang: 'es', label: 'Español' }
]

const config: NativeVideoProps = {
  src: '/videos/demo.mp4',
  alt: 'Product demonstration',
  poster: '/thumbnails/demo.jpg',
  captions,
  controls: true,
  preload: 'metadata'
}

<NativeVideo {...config} />

See Also

On this page