Skip to main content

Media Player

Playback, volume, source selection, and track info for media player entities.

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 passes 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​

The useMediaPlayers hook returns every media player entity Home Assistant knows about:

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>
)
}

Each item in the array is a raw entity object with entity_id, state, and attributes.

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>
)
}