Skip to content
FrameworkStyle

AirPlayButton

Accessible AirPlay toggle button that opens the WebKit playback target picker and reflects session state

Anatomy

<AirPlayButton />

Behavior

Opens the WebKit AirPlay playback target picker and reflects session state. AirPlay is a WebKit-only feature, so the button reports availability: "unsupported" outside Safari (macOS and iOS). On supported platforms availability flips to "available" once Safari discovers at least one AirPlay receiver on the local network, and "unavailable" otherwise.

The toggle is a no-op unless availability is "available" — clicking the button while "unsupported" or "unavailable" will not open the picker. Style the button accordingly (see Styling below) so its appearance matches its actual behavior.

The component consumes the unified remotePlayback store feature alongside CastButton: both buttons drive their state from the same feature, but each only surfaces on its supported platform (WebKit for AirPlay, Chromium for Cast).

WebKit does not expose a "connecting" intermediate state — the state slice flips directly between "disconnected" and "connected" when the AirPlay session changes. When connected, the picker itself acts as the disconnect UI.

Styling

Attribute Values Description
data-airplay-state "disconnected" | "connecting" | "connected" Current AirPlay session state
data-availability "available" | "unavailable" | "unsupported" Whether AirPlay is reachable on the current platform

Use data-airplay-state to swap icons or labels based on the session state:

React renders a <button> element. Add a className and use it as the selector:

/* AirPlay active */
.airplay-button[data-airplay-state="connected"] {
  color: var(--accent);
}

Consider hiding the button on platforms where AirPlay isn’t supported:

.airplay-button[data-availability="unsupported"] {
  display: none;
}

Accessibility

Renders a <button> with an automatic aria-label: “Start AirPlay” when disconnected, “Stop AirPlay” when connected. (The component also supports a "Connecting" label, but WebKit AirPlay never emits a connecting state, so that label is unreachable in practice.) Override with the label prop — either a string or a function that receives the current state. Keyboard activation: Enter / Space.

Examples

Basic Usage

import { AirPlayButton, createPlayer } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';

const Player = createPlayer({ features: videoFeatures });

export default function BasicUsage() {
  return (
    <Player.Provider>
      <Player.Container className="media-container">
        <Video
          src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4"
          autoPlay
          muted
          playsInline
          loop
        />
        <AirPlayButton
          className="media-airplay-button"
          render={(props, state) => {
            const label =
              state.availability === 'unsupported'
                ? 'AirPlay not supported'
                : state.state === 'connected'
                  ? 'Stop AirPlay'
                  : state.availability === 'unavailable'
                    ? 'No AirPlay devices found'
                    : 'Start AirPlay';
            return <button {...props}>{label}</button>;
          }}
        />
      </Player.Container>
    </Player.Provider>
  );
}