# media-quality-radio-group

A menu radio group for selecting video quality

Creates radio items from the player video rendition state and selects automatic or manual quality.

## Import

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

## Anatomy

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

## Behavior

The group is available when the configured media exposes more than one video rendition. The first generated option is `Auto`; selecting it returns control to adaptive bitrate selection. Pass `formatRendition` to customize visible rendition labels.

`<media-quality-radio-group>` generates `<media-menu-radio-item>` children. Add an optional `<template>` with a single `<media-menu-radio-item>` to customize each generated item.

## Styling

| Attribute | Values | Description |
| --- | --- | --- |
| `data-quality` | `string` | Current quality value. |
| `data-disabled` | Present / absent | Present when quality selection is disabled. |
| `data-hidden` | Present / absent | Present when multiple renditions are unavailable. |
| `data-availability` | `"available"` / `"unavailable"` | Whether multiple renditions 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 `Quality`.

## Examples

### Basic usage

**index.html**

```html
<video-player class="video-player">
  <media-container>
    <hlsjs-video
      class="video-media"
      src="https://stream.mux.com/lhnU49l1VGi3zrTAZhDm9LUUxSjpaPW9BL4jY25Kwo4.m3u8"
      autoplay
      crossorigin="anonymous"
      muted
      playsinline
      loop
    ></hlsjs-video>
    <div class="menu-bar">
      <button type="button" commandfor="quality-menu" class="settings-trigger">Quality</button>
      <media-menu id="quality-menu" side="top" align="end" class="menu">
        <media-menu-content>
          <media-quality-radio-group class="menu-group" label="Quality">
            <template>
              <media-menu-radio-item class="menu-item">
                <span>
                  <span data-part="label"></span>
                  <sup data-part="tier" class="menu-tier"></sup>
                </span>
                <span data-part="badge" class="menu-badge"></span>
                <media-menu-item-indicator force-mount class="menu-indicator">✓</media-menu-item-indicator>
              </media-menu-radio-item>
            </template>
          </media-quality-radio-group>
        </media-menu-content>
      </media-menu>
    </div>
  </media-container>
</video-player>
```

**index.css**

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

.video-media {
  width: 100%;
}

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

.menu-bar:has([data-availability="unavailable"]) {
  display: none;
}

.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;
  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-tier {
  margin-left: 2px;
  font-size: 10px;
}

.menu-badge {
  margin-left: auto;
  color: rgba(255, 255, 255, 0.72);
}

.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/media/hlsjs-video';
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/quality-radio-group';
```

## API Reference

### media-quality-radio-group

Menu radio group that generates an Auto `<media-menu-radio-item>` plus one per video rendition, and shares the selected label and availability with an enclosing menu. An optional `<template>` holding one `<media-menu-radio-item>` customizes each generated item; its `data-part` `label`, `tier`, and `badge` descendants receive the rendition's text.

#### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | Whether quality selection is disabled. |
| `formatRendition` (attribute `format-rendition`) | `((rendition: MediaVideoRendition) => Text \| string)` | `formatRenditionLabel` | Custom formatter for visible rendition labels. |
| `label` | `{ key: string; text: string } \| string \| ((state: QualityRadioGroupState) => Text \| string)` | `''` | Custom label for the options group. |

#### State

State is reflected as data attributes for CSS styling.

| Property | Type | Description |
| --- | --- | --- |
| `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-quality` | `string` | Current quality value. |
| `data-disabled` | — | Present when quality selection is disabled. |
| `data-hidden` | — | Present when quality selection is unavailable. |
| `data-availability` | `'available' \| 'unavailable'` | Indicates quality availability (`available` or `unavailable`). |

#### Events

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

---

HTML documentation: https://videojs.org/docs/framework/html/llms.txt
All documentation: https://videojs.org/llms.txt
