# media-captions-radio-group

A menu radio group for selecting caption and subtitle tracks

Creates radio items from the player text track state and selects the showing caption or subtitle track.

## Import

```ts
import '@videojs/html/ui/captions-radio-group';
import '@videojs/html/ui/menu-radio-item';
import '@videojs/html/ui/menu-item-indicator';
```

## Anatomy

```html
<media-captions-radio-group>
  <template>
    <media-menu-radio-item>
      <span data-part="label"></span>
      <media-menu-item-indicator></media-menu-item-indicator>
    </media-menu-radio-item>
  </template>
</media-captions-radio-group>
```

## Behavior

The group is available when the configured media exposes at least one caption or subtitle track. The first generated option is `Off`; selecting it hides captions. Track labels use the track label, then language, then kind. Pass `formatTrack` to customize the visible labels.

`<media-captions-radio-group>` generates `<media-menu-radio-item>` children, including the `Off` item. Add an optional `<template>` with a single `<media-menu-radio-item>` to customize each generated item.

## Styling

| Attribute | Values | Description |
| --- | --- | --- |
| `data-active` | Present / absent | Present when captions are enabled. |
| `data-disabled` | Present / absent | Present when track selection is disabled. |
| `data-hidden` | Present / absent | Present when caption or subtitle tracks are unavailable. |
| `data-availability` | `"available"` / `"unavailable"` | Whether caption or subtitle tracks are available. |

Unavailable groups receive the native `hidden` attribute.

## Accessibility

The group uses the menu radio group pattern.

The element receives an accessible label from the `label` property or defaults to `Captions`.

## Examples

### Basic usage

**index.html**

```html
<video-player class="video-player">
  <media-container>
    <video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoplay muted playsinline loop>
      <track kind="captions" src="/docs/demos/captions-button/captions.vtt" srclang="en" label="English" />
      <track kind="subtitles" src="/docs/demos/captions-button/captions.vtt" srclang="es" label="Spanish" />
    </video>
    <div class="menu-bar">
      <button type="button" commandfor="captions-menu" class="settings-trigger">Captions</button>
      <media-menu id="captions-menu" side="top" align="end" class="menu">
        <media-menu-content>
          <media-captions-radio-group class="menu-group" label="Captions">
            <template>
              <media-menu-radio-item class="menu-item">
                <span data-part="label"></span>
                <media-menu-item-indicator force-mount class="menu-indicator">✓</media-menu-item-indicator>
              </media-menu-radio-item>
            </template>
          </media-captions-radio-group>
        </media-menu-content>
      </media-menu>
    </div>
  </media-container>
</video-player>
```

**index.css**

```css
.video-player media-container {
  position: relative;
  display: block;
}

.video-player media-container video {
  width: 100%;
}

.menu-bar {
  position: absolute;
  right: 10px;
  bottom: 10px;
}

.settings-trigger {
  padding: 6px 16px;
  color: black;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 9999px;
  backdrop-filter: blur(10px);
}

.menu {
  --media-menu-side-offset: 8px;
  box-sizing: border-box;
  display: grid;
  gap: 2px;
  min-width: 180px;
  max-width: var(--media-menu-available-width, var(--media-popover-available-width, none));
  max-height: var(--media-menu-available-height, var(--media-popover-available-height, none));
  padding: 6px;
  overflow: auto;
  overscroll-behavior: none;
  font-size: 14px;
  color: white;
  background: rgba(0, 0, 0, 0.88);
  border-radius: 8px;
  backdrop-filter: blur(10px);
}

.menu-group {
  display: grid;
  gap: 2px;
}

.menu-item {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
  min-height: 32px;
  padding: 0 10px;
  font: inherit;
  color: inherit;
  cursor: pointer;
  background: none;
  border: 0;
  border-radius: 6px;
}

.menu-item[data-highlighted] {
  background: rgba(255, 255, 255, 0.16);
}

.menu-indicator {
  opacity: 0;
}

media-menu-radio-item[aria-checked="true"] .menu-indicator {
  opacity: 1;
}
```

**index.ts**

```ts
import '@videojs/html/video/player';
import '@videojs/html/ui/container';
import '@videojs/html/ui/menu';
import '@videojs/html/ui/menu-content';
import '@videojs/html/ui/menu-radio-item';
import '@videojs/html/ui/menu-item-indicator';
import '@videojs/html/ui/captions-radio-group';
```

## API Reference

### media-captions-radio-group

Menu radio group that generates an Off `<media-menu-radio-item>` plus one per captions and subtitles track, and shares the selected label and availability with an enclosing menu. An optional `<template>` holding one `<media-menu-radio-item>` customizes each generated item.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | Whether track selection is disabled. |
| `formatTrack` (attribute `format-track`) | `((track: MediaTextTrack) => Text \| string)` | `formatTrackLabel` | Custom formatter for visible track labels. |
| `label` | `{ key: string; text: string } \| string \| ((state: CaptionsRadioGroupState) => Text \| string)` | `''` | Custom label for the options group. |

#### State

State is reflected as data attributes for CSS styling.

| Property | Type | Description |
| --- | --- | --- |
| `subtitlesShowing` | `boolean` | Whether captions/subtitles are currently enabled. |
| `label` | `{ key: string; text: string } \| string` | |
| `value` | `string` | Current radio-group value. |
| `options` | `readonly Option[]` | Ordered options displayed by platform adapters. |
| `disabled` | `boolean` | Whether the entire option group is disabled. |
| `hidden` | `boolean` | Whether the option group is hidden because no meaningful selection is available. |
| `availability` | `'available' \| 'unavailable'` | Whether the media exposes a meaningful selection. |

#### Data attributes

| Attribute | Type | Description |
| --- | --- | --- |
| `data-active` | — | Present when captions are enabled. |
| `data-disabled` | — | Present when track selection is disabled. |
| `data-hidden` | — | Present when track selection is unavailable. |
| `data-availability` | `'available' \| 'unavailable'` | Indicates captions availability (`available` or `unavailable`). |

#### Events

| Event | Description |
| --- | --- |
| `value-change` | Fired when the selected value changes. |