Skip to main content

Media Player

Control media players with playback, volume, source selection, and media information.

Quick Example

// Component approach
<MediaPlayer entityId="media_player.living_room_speaker">
{({ isPlaying, toggle, mediaTitle, volumeLevel }) => (
<div>
<p>{mediaTitle || 'No media playing'}</p>
<button onClick={toggle}>
{isPlaying ? 'PAUSE' : 'PLAY'}
</button>
<p>Volume: {Math.round(volumeLevel * 100)}%</p>
</div>
)}
</MediaPlayer>

// Hook approach
const speaker = useMediaPlayer('media_player.living_room_speaker')
<div>
<p>{speaker.mediaTitle || 'No media playing'}</p>
<button onClick={speaker.toggle}>
{speaker.isPlaying ? 'PAUSE' : 'PLAY'}
</button>
<p>Volume: {Math.round(speaker.volumeLevel * 100)}%</p>
</div>

Component API

Basic Usage

import { MediaPlayer } from 'hass-react'

<MediaPlayer entityId="media_player.living_room_speaker">
{(playerProps) => (
// Your UI here
)}
</MediaPlayer>

Render Props

The MediaPlayer component provides these props to your render function:

State Properties

  • isPlaying (boolean) - Whether media is currently playing
  • isPaused (boolean) - Whether media is paused
  • isIdle (boolean) - Whether player is idle (no media loaded)
  • isOff (boolean) - Whether player is turned off
  • isOn (boolean) - Whether player is turned on

Media Information

  • mediaTitle (string | null) - Current media title
  • mediaArtist (string | null) - Current media artist
  • mediaAlbum (string | null) - Current media album
  • mediaContentType (string | null) - Type of media content
  • mediaDuration (number | null) - Total duration in seconds
  • mediaPosition (number | null) - Current position in seconds

Audio Control

  • volumeLevel (number) - Current volume level (0-1)
  • isMuted (boolean) - Whether audio is muted
  • currentSource (string | null) - Current input source
  • sourceList (string[]) - Available input sources
  • currentSoundMode (string | null) - Current sound mode
  • soundModeList (string[]) - Available sound modes

Advanced Features

  • shuffle (boolean | null) - Shuffle mode status
  • repeat (string | null) - Repeat mode (off, one, all)
  • appName (string | null) - Current app name

Support Properties

  • supportsPlay (boolean) - Player supports play
  • supportsPause (boolean) - Player supports pause
  • supportsStop (boolean) - Player supports stop
  • supportsNextTrack (boolean) - Player supports next track
  • supportsPreviousTrack (boolean) - Player supports previous track
  • supportsVolumeSet (boolean) - Player supports volume control
  • supportsVolumeMute (boolean) - Player supports mute/unmute
  • supportsSeek (boolean) - Player supports seeking
  • supportsTurnOn (boolean) - Player supports power on
  • supportsTurnOff (boolean) - Player supports power off
  • supportsSelectSource (boolean) - Player supports source selection
  • supportsSelectSoundMode (boolean) - Player supports sound mode selection
  • supportsShuffle (boolean) - Player supports shuffle
  • supportsRepeat (boolean) - Player supports repeat modes

Control Methods

  • play() - Start playback
  • pause() - Pause playback
  • stop() - Stop playback
  • toggle() - Toggle play/pause
  • nextTrack() - Skip to next track
  • previousTrack() - Skip to previous track
  • turnOn() - Turn player on
  • turnOff() - Turn player off
  • setVolume(volume: number) - Set volume (0-1)
  • toggleMute() - Toggle mute
  • mute() - Mute audio
  • unmute() - Unmute audio
  • selectSource(source: string) - Select input source
  • selectSoundMode(soundMode: string) - Select sound mode
  • setShuffle(shuffle: boolean) - Enable/disable shuffle
  • setRepeat(repeat: string) - Set repeat mode
  • seek(position: number) - Seek to position in seconds
  • playMedia(mediaType: string, mediaId: string) - Play specific media

Entity Properties

  • entityId (string) - The entity ID
  • state (string) - Raw state value from Home Assistant
  • attributes (object) - All entity attributes
  • lastChanged (Date) - When the entity last changed
  • lastUpdated (Date) - When the entity was last updated

Hook API

Basic Usage

import { useMediaPlayer } from 'hass-react'

function MyComponent() {
const player = useMediaPlayer('media_player.living_room_speaker')

// All the same properties as component render props
return <div>{player.isPlaying ? 'PLAYING' : 'PAUSED'}</div>
}

The useMediaPlayer hook returns an object with all the same properties and methods as the component's render props.

List All Media Players

Use the useMediaPlayers hook to retrieve all available media player entities:

import { useMediaPlayers } from 'hass-react'

function MediaPlayerList() {
const mediaPlayers = useMediaPlayers()

return (
<div>
<h2>Available Media Players ({mediaPlayers.length})</h2>
{mediaPlayers.map(player => (
<div key={player.entity_id}>
{player.attributes.friendly_name || player.entity_id}
</div>
))}
</div>
)
}

The useMediaPlayers hook fetches all media player entities from Home Assistant and returns an array of media player objects.

Examples

Simple Media Control

<MediaPlayer entityId="media_player.bedroom_speaker">
{({ isPlaying, isPaused, isOff, play, pause, stop, turnOn, mediaTitle, mediaArtist, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>

<div>
<strong>{mediaTitle || 'No media'}</strong>
{mediaArtist && <p>by {mediaArtist}</p>}
</div>

<div>
{isOff ? (
<button onClick={turnOn}>Turn On</button>
) : (
<>
<button onClick={play} disabled={isPlaying}>
Play
</button>
<button onClick={pause} disabled={!isPlaying}>
Pause
</button>
<button onClick={stop}>
Stop
</button>
</>
)}
</div>
</div>
)}
</MediaPlayer>

Volume Control

<MediaPlayer entityId="media_player.kitchen_speaker">
{({ volumeLevel, isMuted, setVolume, toggleMute, supportsVolumeSet, supportsVolumeMute, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>

{supportsVolumeSet && (
<div>
<label>Volume: {Math.round(volumeLevel * 100)}%</label>
<input
type="range"
min="0"
max="100"
value={volumeLevel * 100}
onChange={(e) => setVolume(parseInt(e.target.value) / 100)}
/>
</div>
)}

{supportsVolumeMute && (
<button onClick={toggleMute}>
{isMuted ? 'Unmute' : 'Mute'}
</button>
)}
</div>
)}
</MediaPlayer>

Track Navigation

<MediaPlayer entityId="media_player.spotify">
{({
isPlaying, toggle, nextTrack, previousTrack,
supportsNextTrack, supportsPreviousTrack,
mediaTitle, mediaArtist, mediaAlbum, attributes
}) => (
<div>
<h3>{attributes.friendly_name}</h3>

<div>
<strong>{mediaTitle || 'No track'}</strong>
{mediaArtist && <p>{mediaArtist}</p>}
{mediaAlbum && <p>Album: {mediaAlbum}</p>}
</div>

<div>
{supportsPreviousTrack && (
<button onClick={previousTrack}>Previous</button>
)}

<button onClick={toggle}>
{isPlaying ? 'Pause' : 'Play'}
</button>

{supportsNextTrack && (
<button onClick={nextTrack}>Next</button>
)}
</div>
</div>
)}
</MediaPlayer>

Progress Bar with Seeking

<MediaPlayer entityId="media_player.music_player">
{({ mediaPosition, mediaDuration, seek, supportsSeek, mediaTitle, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>
<p>{mediaTitle || 'No media'}</p>

{supportsSeek && mediaDuration && (
<div>
<input
type="range"
min="0"
max={mediaDuration}
value={mediaPosition || 0}
onChange={(e) => seek(parseInt(e.target.value))}
/>

<div>
{Math.floor((mediaPosition || 0) / 60)}:
{String(Math.floor((mediaPosition || 0) % 60)).padStart(2, '0')} /
{Math.floor(mediaDuration / 60)}:
{String(Math.floor(mediaDuration % 60)).padStart(2, '0')}
</div>
</div>
)}
</div>
)}
</MediaPlayer>

Source Selection

<MediaPlayer entityId="media_player.av_receiver">
{({ currentSource, sourceList, selectSource, supportsSelectSource, attributes }) => (
<div>
<h3>{attributes.friendly_name}</h3>
<p>Current Source: {currentSource}</p>

{supportsSelectSource && sourceList.length > 0 && (
<div>
<label>Select Source:</label>
<select value={currentSource || ''} onChange={(e) => selectSource(e.target.value)}>
{sourceList.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</div>
)}
</div>
)}
</MediaPlayer>

Shuffle and Repeat

<MediaPlayer entityId="media_player.music_service">
{({
shuffle, repeat, setShuffle, setRepeat,
supportsShuffle, supportsRepeat, attributes
}) => (
<div>
<h3>{attributes.friendly_name}</h3>

{supportsShuffle && (
<label>
<input
type="checkbox"
checked={shuffle || false}
onChange={(e) => setShuffle(e.target.checked)}
/>
Shuffle
</label>
)}

{supportsRepeat && (
<div>
<label>Repeat:</label>
<select value={repeat || 'off'} onChange={(e) => setRepeat(e.target.value)}>
<option value="off">Off</option>
<option value="one">One</option>
<option value="all">All</option>
</select>
</div>
)}
</div>
)}
</MediaPlayer>

Multiple Players

function MediaPlayerPanel() {
const players = [
'media_player.living_room',
'media_player.kitchen',
'media_player.bedroom'
]

return (
<div>
<h2>Media Players</h2>
{players.map(entityId => (
<MediaPlayer key={entityId} entityId={entityId}>
{({ isPlaying, toggle, mediaTitle, volumeLevel, attributes }) => (
<div>
<strong>{attributes.friendly_name}</strong>
<br />
Playing: {mediaTitle || 'Nothing'}
<br />
Volume: {Math.round(volumeLevel * 100)}%
<br />
<button onClick={toggle}>
{isPlaying ? 'Pause' : 'Play'}
</button>
</div>
)}
</MediaPlayer>
))}
</div>
)
}

Using Hooks

import { useMediaPlayer } from 'hass-react'

function MediaPlayerCard({ entityId }) {
const player = useMediaPlayer(entityId)

const getStatusText = () => {
if (player.isOff) return 'OFF'
if (player.isPlaying) return 'PLAYING'
if (player.isPaused) return 'PAUSED'
if (player.isIdle) return 'IDLE'
return 'UNKNOWN'
}

const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${String(secs).padStart(2, '0')}`
}

return (
<div>
<h3>{player.attributes.friendly_name}</h3>

<div>Status: {getStatusText()}</div>

{player.mediaTitle && (
<div>
<strong>{player.mediaTitle}</strong>
{player.mediaArtist && <div>{player.mediaArtist}</div>}
</div>
)}

{player.mediaPosition !== null && player.mediaDuration !== null && (
<div>
{formatTime(player.mediaPosition)} / {formatTime(player.mediaDuration)}
</div>
)}

<div>
<button onClick={player.toggle} disabled={player.isOff}>
{player.isPlaying ? 'Pause' : 'Play'}
</button>

{player.supportsNextTrack && (
<button onClick={player.nextTrack}>Next</button>
)}
</div>

{player.supportsVolumeSet && (
<div>
Volume: {Math.round(player.volumeLevel * 100)}%
<input
type="range"
min="0"
max="100"
value={player.volumeLevel * 100}
onChange={(e) => player.setVolume(parseInt(e.target.value) / 100)}
/>
</div>
)}

<p>Last updated: {player.lastUpdated.toLocaleTimeString()}</p>
</div>
)
}