MuteButton
Accessible mute/unmute button with keyboard support and volume state reflection
Import
import { MuteButton } from '@videojs/react';import '@videojs/html/ui/mute-button';Anatomy
<MuteButton /><media-mute-button></media-mute-button>Behavior
Toggles mute on and off, and exposes a derived volumeLevel based on the current volume and mute state.
Mute availability is separate from volume-level availability because some media can accept a mute command without supporting volume changes. When mute is unavailable or unsupported, the HTML custom element receives the native hidden attribute and the React component returns null. Toggling is also ignored while mute is unavailable.
Styling
| Attribute | Values | Description |
|---|---|---|
data-muted |
Present / absent | Present when the media is muted |
data-volume-level |
"off" | "low" | "medium" | "high" |
Current volume level |
data-availability |
"available" | "unavailable" | "unsupported" |
Whether the media can be muted |
data-hidden |
Present / absent | Present on the HTML element while mute is unavailable or unsupported |
Style the button based on muted state:
media-mute-button[data-muted] .icon-muted { display: inline; }
media-mute-button:not([data-muted]) .icon-unmuted { display: inline; }React renders a <button> element. Add a className to style it:
.mute-button[data-muted] .icon-muted { display: inline; }
.mute-button:not([data-muted]) .icon-unmuted { display: inline; }Use data-volume-level for multi-level icon switching:
media-mute-button[data-volume-level="off"] .icon-off { display: inline; }
media-mute-button[data-volume-level="low"] .icon-low { display: inline; }
media-mute-button[data-volume-level="medium"] .icon-medium { display: inline; }
media-mute-button[data-volume-level="high"] .icon-high { display: inline; }.mute-button[data-volume-level="off"] .icon-off { display: inline; }
.mute-button[data-volume-level="low"] .icon-low { display: inline; }
.mute-button[data-volume-level="medium"] .icon-medium { display: inline; }
.mute-button[data-volume-level="high"] .icon-high { display: inline; }Unavailable and unsupported buttons are hidden automatically. No availability selector or extra hiding CSS is required.
Accessibility
Renders a <button> with an automatic aria-label: “Unmute” when muted, “Mute” when unmuted. Override with the label prop. Keyboard activation: Enter / Space.
Examples
Basic Usage
import { Container, createPlayer, MuteButton } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';
const { Player } = createPlayer({ features: videoFeatures });
export default function BasicUsage() {
return (
<Player>
<Container className="media-container">
<Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoPlay muted playsInline loop />
<MuteButton
className="media-mute-button"
render={(props, state) => <button {...props}>{state.muted ? 'Unmute' : 'Mute'}</button>}
/>
</Container>
</Player>
);
}
.media-container {
position: relative;
}
.media-container video {
width: 100%;
}
.media-mute-button {
position: absolute;
bottom: 10px;
left: 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);
}
<video-player class="video-player">
<media-container>
<video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoplay muted playsinline loop></video>
<media-mute-button class="media-mute-button">
<span class="muted">Unmute</span>
<span class="unmuted">Mute</span>
</media-mute-button>
</media-container>
</video-player>
.video-player media-container {
position: relative;
}
.video-player media-container video {
width: 100%;
}
.media-mute-button {
position: absolute;
bottom: 10px;
left: 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-mute-button .muted {
display: none;
}
.media-mute-button .unmuted {
display: none;
}
.media-mute-button[data-muted] .muted {
display: inline;
}
.media-mute-button:not([data-muted]) .unmuted {
display: inline;
}
import '@videojs/html/video/player';
import '@videojs/html/ui/container';
import '@videojs/html/ui/mute-button';
Volume Levels
import { Container, createPlayer, MuteButton } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';
const { Player } = createPlayer({ features: videoFeatures });
export default function VolumeLevels() {
return (
<Player>
<Container className="media-container">
<Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoPlay muted playsInline loop />
<MuteButton
className="media-mute-button"
render={(props, state) => (
<button {...props}>
{state.volumeLevel === 'off'
? 'Off'
: state.volumeLevel === 'low'
? 'Low'
: state.volumeLevel === 'medium'
? 'Medium'
: 'High'}
</button>
)}
/>
</Container>
</Player>
);
}
.media-container {
position: relative;
}
.media-container video {
width: 100%;
}
.media-mute-button {
position: absolute;
bottom: 10px;
left: 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);
}
<video-player class="video-player">
<media-container>
<video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoplay muted playsinline loop></video>
<media-mute-button class="media-mute-button">
<span class="level-off">Off</span>
<span class="level-low">Low</span>
<span class="level-medium">Medium</span>
<span class="level-high">High</span>
</media-mute-button>
</media-container>
</video-player>
.video-player media-container {
position: relative;
}
.video-player media-container video {
width: 100%;
}
.media-mute-button {
position: absolute;
bottom: 10px;
left: 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-mute-button .level-off,
.media-mute-button .level-low,
.media-mute-button .level-medium,
.media-mute-button .level-high {
display: none;
}
.media-mute-button[data-volume-level="off"] .level-off {
display: inline;
}
.media-mute-button[data-volume-level="low"] .level-low {
display: inline;
}
.media-mute-button[data-volume-level="medium"] .level-medium {
display: inline;
}
.media-mute-button[data-volume-level="high"] .level-high {
display: inline;
}
import '@videojs/html/video/player';
import '@videojs/html/ui/container';
import '@videojs/html/ui/mute-button';
API Reference
Props
| Prop | Type | Default | Details |
|---|---|---|---|
disabled | boolean | false | |
| |||
label | object | '' | |
| |||
State
render, className, and style props.| Property | Type | Details |
|---|---|---|
muted | boolean | |
| ||
label | { key: string; text: string } | string | |
volumeLevel | 'off' | 'low' | 'medium' | 'high' | |
| ||
availability | MediaFeatureAvailability | |
| ||
Data attributes
| Attribute | Type | Details |
|---|---|---|
data-muted | ||
| ||
data-volume-level | 'off' | 'low' | 'medium' | 'high' | |
| ||
data-availability | MediaFeatureAvailability | |
| ||