# media-cast-button

Accessible Cast toggle button with state reflection and keyboard support

## Import

```ts
import '@videojs/html/ui/cast-button';
```

## Anatomy

```html
<media-cast-button></media-cast-button>
```

## Behavior

Toggles a Google Cast session. Clicking the button while `disconnected` opens the Cast device picker; clicking while `connected` ends the session.

The button derives its presentation from `availability`:

- **`"unsupported"`** — the element receives the native `hidden` attribute.
- **`"unavailable"`** — the button remains visible and focusable with `aria-disabled="true"` and `data-disabled`, but does not open the picker. This lets a tooltip explain that no Cast device is reachable.
- **`"available"`** — the button is fully interactive unless the `disabled` prop is set.

Configurable Cast sessions come from the [Google Cast extension](https://videojs.org/docs/framework/html/reference/components/google-cast). Add it to the player next to your media element; without it the button drives the browser’s native Remote Playback API instead, which offers no receiver or load-request configuration. See [Cast to AirPlay and Chromecast](https://videojs.org/docs/framework/html/guides/casting) for the complete setup.

## Styling

Style based on cast and disabled state:

```css
/* During an active session */
media-cast-button[data-cast-state="connected"] {
  color: blue;
}

/* Cast is supported, but no device is reachable */
media-cast-button[data-disabled] {
  cursor: not-allowed;
  opacity: 0.5;
}
```

Unsupported buttons are hidden automatically. No availability selector or extra hiding CSS is required.

## Accessibility

Renders a `<button>` with an automatic `aria-label`:

| Cast state | Default label |
| --- | --- |
| `'disconnected'` | “Start casting” |
| `'connecting'` | “Connecting” |
| `'connected'` | “Stop casting” |

Override with the `label` prop. Keyboard activation: Enter / Space.

## Examples

### Basic Usage

**index.html**

```html
<video-player class="video-player">
  <media-container>
    <hlsjs-video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM.m3u8" autoplay muted playsinline loop></hlsjs-video>
    <google-cast></google-cast>
    <media-cast-button class="media-cast-button">
      <span class="connected">Stop casting</span>
      <span class="disconnected">Start casting</span>
    </media-cast-button>
  </media-container>
</video-player>
```

**index.css**

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

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

.media-cast-button {
  position: absolute;
  right: 10px;
  bottom: 10px;
  padding-block: 8px;
  padding-inline: 20px;
  color: black;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 9999px;
  backdrop-filter: blur(10px);
}

.media-cast-button[data-disabled] {
  cursor: not-allowed;
  opacity: 0.5;
  filter: grayscale(1);
}

.media-cast-button .connected {
  display: none;
}
.media-cast-button .disconnected {
  display: none;
}
.media-cast-button[data-cast-state="connected"] .connected {
  display: inline;
}
.media-cast-button:not([data-cast-state="connected"]) .disconnected {
  display: inline;
}
```

**index.ts**

```ts
import '@videojs/html/video/player';
import '@videojs/html/extensions/google-cast';
import '@videojs/html/ui/container';
import '@videojs/html/media/hlsjs-video';
import '@videojs/html/ui/cast-button';
```

## API Reference

### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | Whether the button is disabled. |
| `label` | `{ key: string; text: string } \| string \| ((state: CastButtonState) => Text \| string)` | `''` | Custom label for the button. |

### State

State is reflected as data attributes for CSS styling.

| Property | Type | Description |
| --- | --- | --- |
| `label` | `{ key: string; text: string } \| string` | |
| `connection` | `'disconnected' \| 'connecting' \| 'connected'` | Current cast connection state (`disconnected`, `connecting`, or `connected`). |
| `availability` | `'available' \| 'unavailable' \| 'unsupported'` | Whether casting is `available` (a device is reachable), `unavailable` (no device), or `unsupported`. |
| `disabled` | `boolean` | Non-interactive but still focusable (mirrors `aria-disabled`). |
| `hidden` | `boolean` | Whether the button is hidden because the feature is unsupported. |

### Data attributes

| Attribute | Type | Description |
| --- | --- | --- |
| `data-cast-state` | `'disconnected' \| 'connecting' \| 'connected'` | Current remote playback connection state. |
| `data-availability` | `'available' \| 'unavailable' \| 'unsupported'` | Whether remote playback can be requested on this platform. |
| `data-disabled` | — | Present when the button is non-interactive (mirrors `aria-disabled`). |
| `data-hidden` | — | Present when the button is hidden because the feature is unsupported. |

---

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