Captions Configuration

Learn how to add multi-language subtitle support to your video player using WebVTT format, configure caption tracks, and customize caption appearance for enhanced accessibility.

Captions and subtitles make your video content accessible to a broader audience, including viewers who are deaf or hard of hearing, non-native speakers, and those watching in sound-sensitive environments. The video player provides robust subtitle support through the WebVTT format, allowing you to offer multi-language captions with custom styling and intelligent positioning.

Understanding Caption Support

The player's caption system goes beyond basic subtitle display. It includes several sophisticated features designed to enhance the viewing experience: multi-language support allows viewers to choose their preferred language from available options, custom styling enables you to match captions to your brand or improve readability, intelligent auto-positioning ensures captions don't overlap with player controls, and keyboard navigation lets users cycle through available languages quickly.

The player uses WebVTT as its caption format. WebVTT stands for Web Video Text Tracks, a standard format for displaying timed text in HTML5 video. This format is widely supported, easy to create and edit, supports styling and positioning, and includes features like cue settings for precise control over caption appearance.

Basic Caption Configuration

Adding captions to your player requires creating an array of caption track objects and passing them through the captions prop. Each track represents a single language or caption variation.

Single Language Captions

Start with a simple single-language configuration:

src/components/VideoPlayer.jsx
import { CustomVideoPlayer } from "@ntxmjs/react-custom-video-player";

function VideoPlayer() {
  const captions = [
    {
      src: "https://example.com/subtitles/video-en.vtt",
      srclang: "en",
      label: "English",
      default: true,
    },
  ];

  return (
    <CustomVideoPlayer
      src="https://example.com/video.m3u8"
      poster="https://example.com/poster.jpg"
      icons={playerIcons}
      captions={captions}
    />
  );
}

This configuration adds English subtitles to your video. The src property points to the WebVTT file containing the caption text and timing information. The srclang property specifies the language code using the ISO 639-1 standard. The label property defines how the caption option appears in the player's subtitle menu. Setting default to true makes this track active when the video loads.

Understanding the Default Track: When multiple caption tracks are available, exactly one should have default: true. This track will be active when the player first loads. If no track is marked as default, the player starts with captions disabled, and users must manually enable them through the settings menu.

Multi-Language Captions

For international audiences, provide captions in multiple languages:

src/components/VideoPlayer.jsx
import { CustomVideoPlayer } from "@ntxmjs/react-custom-video-player";

function VideoPlayer() {
  const captions = [
    {
      src: "https://example.com/subtitles/video-en.vtt",
      srclang: "en",
      label: "English",
      default: true,
    },
    {
      src: "https://example.com/subtitles/video-es.vtt",
      srclang: "es",
      label: "Spanish",
      default: false,
    },
    {
      src: "https://example.com/subtitles/video-fr.vtt",
      srclang: "fr",
      label: "French",
      default: false,
    },
    {
      src: "https://example.com/subtitles/video-de.vtt",
      srclang: "de",
      label: "German",
      default: false,
    },
  ];

  return (
    <CustomVideoPlayer
      src="https://example.com/video.m3u8"
      poster="https://example.com/poster.jpg"
      icons={playerIcons}
      captions={captions}
    />
  );
}

This configuration provides captions in four languages. Users can switch between languages using the player's subtitle menu or by pressing the C key to cycle through available options. The player remembers the user's language preference throughout the session.

Language Code Reference: Use ISO 639-1 two-letter codes for common languages. English is "en", Spanish is "es", French is "fr", German is "de", Italian is "it", Portuguese is "pt", Japanese is "ja", Chinese is "zh", Korean is "ko", and Arabic is "ar". For regional variants, use extended codes like "en-US" for American English or "pt-BR" for Brazilian Portuguese.

Working with WebVTT Files

WebVTT files contain the caption text along with timing information. Understanding the format helps you create or edit caption files effectively.

WebVTT File Structure

A basic WebVTT file looks like this:

subtitles/video-en.vtt
WEBVTT

00:00:00.000 --> 00:00:04.000
Welcome to our video player tutorial.

00:00:04.500 --> 00:00:08.000
We'll show you how to add captions
to enhance accessibility.

00:00:08.500 --> 00:00:12.000
Captions make your content available
to a wider audience.

00:00:12.500 --> 00:00:16.000
Let's explore the configuration options.

The file begins with the WEBVTT declaration, which must be the first line. Each caption entry, called a "cue," consists of a timestamp range showing when the caption should appear and disappear, followed by the caption text. Blank lines separate individual cues.

Timestamp Format: Timestamps use the format HH:MM:SS.mmm where hours are optional if under one hour, minutes and seconds are required and zero-padded, and milliseconds provide precise timing. The arrow --> separates start and end times. For example, 00:00:15.500 --> 00:00:18.750 displays a caption from 15.5 seconds to 18.75 seconds.

Advanced WebVTT Features

WebVTT supports additional features for more sophisticated captioning:

subtitles/video-advanced.vtt
WEBVTT

NOTE
This is a comment that won't be displayed

1
00:00:00.000 --> 00:00:04.000
Welcome to our video player tutorial.

2
00:00:04.500 --> 00:00:08.000 align:middle position:50%
Centered caption with specific positioning.

speaker-1
00:00:08.500 --> 00:00:12.000
<v Speaker 1>Dialogue with speaker identification.</v>

sound-effect
00:00:12.000 --> 00:00:13.000
[<i>music playing</i>]

This example demonstrates several advanced features. You can add numeric or text identifiers before timestamps to label specific cues, though this is optional. NOTE blocks allow you to include comments that won't be displayed. Cue settings like align and position control where captions appear on screen. The <v> tag identifies speakers in dialogue, while the <i> tag adds italic formatting for emphasis or sound effects.

Creating Caption Files:

Professional caption files require precise timing and proper formatting. Consider using subtitle editing software like Subtitle Edit, Aegisub, or online tools like Kapwing for creating and synchronizing captions. These tools provide timeline views and waveform displays that make timing adjustments easier than manual editing.

Caption Track Properties

Each caption track object supports four essential properties that control how the track behaves and appears in the player.

The src Property

The src property specifies the URL of the WebVTT file. This can be an absolute URL pointing to any accessible server, a relative URL within your application, or a CDN URL for globally distributed caption files.

const captions = [
  {
    src: "https://cdn.example.com/captions/video-en.vtt", // CDN URL
    srclang: "en",
    label: "English",
    default: true,
  },
  {
    src: "/public/captions/video-es.vtt", // Relative URL
    srclang: "es",
    label: "Spanish",
    default: false,
  },
];

File Hosting Considerations: Caption files are typically small text files, but they must be accessible via HTTP/HTTPS. If hosting captions on a different domain than your video, ensure proper CORS headers are configured on the caption server. Without correct CORS settings, browsers will block the caption files, preventing them from displaying.

The srclang Property

The srclang property identifies the caption track's language using standard language codes. This enables the browser and assistive technologies to properly handle the text, affects how the player displays language options in the subtitle menu, and allows users to pre-select their preferred language if you implement language preference storage.

const captions = [
  { src: "captions-en.vtt", srclang: "en", label: "English", default: true },
  {
    src: "captions-en-GB.vtt",
    srclang: "en-GB",
    label: "English (UK)",
    default: false,
  },
  {
    src: "captions-es-MX.vtt",
    srclang: "es-MX",
    label: "Spanish (Mexico)",
    default: false,
  },
];

For region-specific variants, use extended language codes. This is particularly useful when caption styles, terminology, or spelling differ between regions.

The label Property

The label property defines the user-visible text in the subtitle selection menu. Choose labels that are clear and immediately recognizable to your audience.

const captions = [
  { src: "captions-en.vtt", srclang: "en", label: "English", default: true },
  {
    src: "captions-en-cc.vtt",
    srclang: "en",
    label: "English (CC)",
    default: false,
  },
  {
    src: "captions-en-sdh.vtt",
    srclang: "en",
    label: "English (SDH)",
    default: false,
  },
];

This example shows different caption variations for the same language. "CC" indicates closed captions, which include sound effects and speaker identification. "SDH" means Subtitles for the Deaf and Hard of hearing, similar to closed captions but formatted for viewing subtitles rather than captions.

Label Best Practices: Write labels in the target language when possible. For English speakers choosing from multiple languages, seeing "EspaƱol" is more recognizable than "Spanish." If space allows, include descriptive information like "English (Descriptive)" for audio description captions or "English (Simplified)" for easier-to-read versions.

The default Property

The default property determines which caption track is active when the video initially loads. Only one track should have default: true.

const captions = [
  { src: "captions-en.vtt", srclang: "en", label: "English", default: true },
  { src: "captions-es.vtt", srclang: "es", label: "Spanish", default: false },
  { src: "captions-fr.vtt", srclang: "fr", label: "French", default: false },
];

If you want captions disabled by default, set default: false for all tracks. Users can then enable captions manually through the player controls.

Dynamic Caption Loading

For applications with extensive caption libraries or user-generated content, you might need to load caption configurations dynamically based on the video being played or user preferences.

src/components/DynamicVideoPlayer.jsx
import { CustomVideoPlayer } from "@ntxmjs/react-custom-video-player";
import { useState, useEffect } from "react";

function DynamicVideoPlayer({ videoId }) {
  const [captions, setCaptions] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function loadCaptions() {
      try {
        const response = await fetch(`/api/videos/${videoId}/captions`);
        const captionData = await response.json();

        const formattedCaptions = captionData.map((caption, index) => ({
          src: caption.url,
          srclang: caption.language,
          label: caption.displayName,
          default: index === 0, // First language is default
        }));

        setCaptions(formattedCaptions);
      } catch (error) {
        console.error("Failed to load captions:", error);
        setCaptions([]); // Empty array means no captions
      } finally {
        setLoading(false);
      }
    }

    loadCaptions();
  }, [videoId]);

  if (loading) {
    return <div>Loading player...</div>;
  }

  return (
    <CustomVideoPlayer
      src={`/videos/${videoId}.m3u8`}
      poster={`/thumbnails/${videoId}.jpg`}
      icons={playerIcons}
      captions={captions}
    />
  );
}

This component fetches caption information from an API endpoint when the video ID changes. The API returns caption metadata, which is transformed into the format expected by the player. This approach centralizes caption management, making it easier to add or update caption files without modifying code.

API Response Structure: Your caption API should return data that includes the WebVTT file URL, the language code, the display name for the subtitle menu, and optionally whether this should be the default track. Transform this data into the player's expected format before passing it to the captions prop.

User Experience Considerations

Caption implementation involves more than just technical configuration. Consider these aspects to ensure the best experience for your viewers.

Caption Availability

Always inform users about available caption options. The player automatically displays a subtitle button in the controls when captions are configured, but you might want to provide additional context in your interface.

src/components/VideoWithInfo.jsx
import { CustomVideoPlayer } from "@ntxmjs/react-custom-video-player";

function VideoWithInfo() {
  const captions = [
    { src: "captions-en.vtt", srclang: "en", label: "English", default: true },
    { src: "captions-es.vtt", srclang: "es", label: "Spanish", default: false },
    { src: "captions-fr.vtt", srclang: "fr", label: "French", default: false },
  ];

  const availableLanguages = captions.map(c => c.label).join(", ");

  return (
    <div className="video-container">
      <div className="video-header">
        <h2>Video Title</h2>
        <p>Subtitles available in: {availableLanguages}</p>
      </div>
      <CustomVideoPlayer
        src="https://example.com/video.m3u8"
        poster="https://example.com/poster.jpg"
        icons={playerIcons}
        captions={captions}
      />
    </div>
  );
}

Explicitly listing available languages helps users know what to expect before they start watching, particularly important for international audiences searching for content in their language.

Default Language Selection

Consider implementing logic to automatically select the most appropriate caption language based on the user's browser language or stored preferences.

src/components/SmartVideoPlayer.jsx
import { CustomVideoPlayer } from "@ntxmjs/react-custom-video-player";

function SmartVideoPlayer() {
  const browserLanguage = navigator.language.split("-")[0]; // e.g., "en" from "en-US"

  const captions = [
    { src: "captions-en.vtt", srclang: "en", label: "English", default: false },
    { src: "captions-es.vtt", srclang: "es", label: "Spanish", default: false },
    { src: "captions-fr.vtt", srclang: "fr", label: "French", default: false },
  ].map(caption => ({
    ...caption,
    default: caption.srclang === browserLanguage,
  }));

  // Fallback to first caption if no match
  if (!captions.some(c => c.default)) {
    captions[0].default = true;
  }

  return (
    <CustomVideoPlayer
      src="https://example.com/video.m3u8"
      poster="https://example.com/poster.jpg"
      icons={playerIcons}
      captions={captions}
    />
  );
}

This implementation automatically selects captions matching the user's browser language. If no match is found, it defaults to the first available language. This provides a more personalized experience without requiring users to manually select their preferred language.

Accessibility Impact:

Captions significantly improve accessibility. They help viewers who are deaf or hard of hearing, assist non-native speakers in understanding content, enable viewing in sound-sensitive environments like offices or public transportation, and improve comprehension and retention for all viewers. The Web Content Accessibility Guidelines recommend providing captions for all prerecorded audio content.

Customizing Caption Appearance

While the player provides default caption styling that works well in most situations, you can customize caption appearance through the theme system to match your brand or improve readability in specific contexts.

The theme's customCaptionStyle object controls caption appearance:

src/components/StyledVideoPlayer.jsx
import { CustomVideoPlayer } from "@ntxmjs/react-custom-video-player";

function StyledVideoPlayer() {
  const customTheme = {
    // ...more theme values here
    colors: {
      customCaptionStyle: {
        background: "rgba(40, 40, 40, 0.9)",
        color: "#ffffff",
        fontSize: "clamp(12px, 1.8vw, 18px)",
        fontWeight: 600,
        padding: "8px 12px",
        borderRadius: "4px",
        backdropFilter: "blur(6px)",
        boxShadow: "0 2px 8px rgba(0, 0, 0, 0.5)",
        lineHeight: 1.5,
        textAlign: "center",
      },
    },
  };

  return (
    <CustomVideoPlayer
      src="https://example.com/video.m3u8"
      poster="https://example.com/poster.jpg"
      icons={playerIcons}
      captions={captions}
      theme={customTheme}
    />
  );
}

This configuration creates captions with enhanced readability: a semi-transparent dark background with backdrop blur for contrast against any video content, white text with medium font weight for clarity, responsive font sizing that adapts to viewport width, comfortable padding and rounded corners for visual polish, and a subtle shadow to separate captions from the video.

Readability Guidelines: Ensure sufficient contrast between caption text and background. White or yellow text on dark backgrounds typically provides the best readability. Use font sizes that remain legible across device sizes—the clamp() function helps maintain readability from mobile phones to large displays. Avoid overly decorative fonts that might be harder to read quickly.

Keyboard Navigation

The player includes built-in keyboard shortcuts for caption control. Users can press C to cycle through available caption tracks, including an "Off" state that disables captions entirely.

Caption Cycling Behavior:
1. English (default, active)
2. Spanish (user presses C)
3. French (user presses C)
4. Off (user presses C)
5. English (user presses C, cycling back)

This cycling behavior makes it easy for users to quickly switch between languages or temporarily disable captions without navigating through menus. The current caption state is remembered throughout the session.

Troubleshooting Caption Issues

If captions don't appear or behave incorrectly, check these common issues:

Captions Not Displaying: Verify the WebVTT file URL is accessible by opening it directly in a browser. Check browser console for CORS errors if captions are hosted on a different domain. Ensure the WebVTT file starts with the WEBVTT declaration and uses proper formatting.

Incorrect Timing: Confirm timestamps in the WebVTT file match the actual video content. Timestamps may be offset if the video file was trimmed or edited after captions were created. Use subtitle editing software to adjust timing.

Character Encoding Issues: Save WebVTT files with UTF-8 encoding to support international characters and special symbols. Files saved with other encodings may display incorrectly or fail to load.

Multiple Captions Showing: Verify only one caption track has default: true. If multiple tracks are marked as default, the browser behavior becomes unpredictable.

Caption Menu Empty: Ensure the captions array is not empty and contains valid track objects. Check that all required properties are present for each track.

Next Steps

With captions configured, explore these related features:

Theming: Customize caption styling along with other player appearance options to create a cohesive visual experience.

Keyboard Shortcuts: Learn about all available keyboard controls, including caption cycling and other power-user features.

Props: Discover additional configuration options that complement caption functionality.

Caption support makes your video content more accessible and valuable to viewers worldwide. Whether providing single-language subtitles or comprehensive multi-language options, the player's caption system delivers a professional viewing experience while maintaining ease of implementation and customization.