As @gaearon mentioned, React does not guarantee an attribute will be set, so probably this is not a bug.
If I understand well, react will ensure the property is set anyway.
Current behaviour
React renders the html <video />
element without the attribute muted
when explicitly passed.
Demo time
In this pen I made a simple example setting muted
to the element and obtaining the result below:
Actually the property is set well, since the original medial file has an audio track and in the pen result is muted.
The point
I think is most a _specific need_ than the _expected behaviour_.
From the functionality POV, it is absolutely ok, my _Component_ renders a <video />
muted as requested and so on.
But there are _browsers_ and _policies_, more specifically related to this issue, Webkit and the New updated one year ago, with some interesting changes for the <video />
element.
The part interested is
<video muted>
elements will also be allowed to autoplay without a user gesture.
So, the _specific need_ is to have the _explicit_ attribute
to tell the browser that this video could be autoPlay
ed.
There's a similar issue
The muted
property is live just like value
for inputs and reflects the current value. But the muted
attribute reflects the initial state of the component.
So I think the current behavior is wrong, because <video muted />
should force it to always be muted then, just like <input value="foo" />
forces it to always be "foo"
. So one way to resolve this is to start from scratch; introduce defaultMuted
property which maps to the attribute only. Then there should be a muted
property which is controlled (just like input value
) and there needs to be a callback to go with that e.g. onMutedChange
. However! Mute is just equal to volume being zero, so the DOM only exposes the volumechange
event.
So perhaps a more DOM-truthful and minimal implementation would be to have muted
be the attribute and reflect only the initial mute state.
Then React can take it further and also support a special-property volume
and its corresponding event onVolumeChange
. But this is a slippery slope and there are tons of such properties that should be added then (and increasingly mixing both behaviors in React is a much larger discussion). Elsewhere we recommend that people simply manually set properties via JS to control elements and I think the same general recommendation works best here too, manually set the properties and expose your fancy video player as a React component if you want to reuse it.
tl;dr IMHO yes, muted
should set the attribute only, so that it only sets the initial state of the element.
I am facing the same issue with Android 4.4, according to new (from a year ago), muted
attribute needs to be present.
@gaearon This should be an easy fix if you're OK with the direction (making muted
set the attribute instead), although there is potential to break some existing code if someone decided to implement their own mute button and rely on this prop.
Since defaultMuted
is already a spec-defined property reflecting the muted
attribute, it would make sense to let users utilize this API. The React API is already property-focused, so it's not a big leap. This would be the least complex change, and shouldn't be breaking.
@aweary Any progress on this?
@aweary Same question here, we need the muted attribute to be passed to the video tag to allow autoplaying on mobile devices. Has there been any progress in this direction?
Thank you!
folks progress on an Issue is generally visible and takes the form of a PR. If you don't see a linked PR or updates on an issue assume there is no more progress.
It's unclear what the path forward is for this to me. We don't really have way of saying "sync the attribute once and then use the property" and I don't know that adding said logic is even a good idea...
It's unclear what the path forward is for this to me. We don't really have way of saying "sync the attribute once and then use the property" and I don't know that adding said logic is even a good idea...
@jquense I think I understand your point, but inputs have both value
and defaultValue
. This is exactly the same thing, there should probably be a defaultMuted
and muted
. It's a "live" value and needs to be special-cased in the same way, that or otherwise just have muted
prop which sets the attribute but that means users need to manually access the muted
property if they want to control it precisely (just like you can with defaultValue
for inputs), which is also fine.
Personally, just having muted
set the attribute and leaving everything else up to the user is perfectly fine (and IMHO how input should have been implemented too).
I'm hesitant to change muted
to act like value
; we want to get away from that special-cased behavior, since it's caused a number of problems. Of course, muted
would likely be much less problematic since it's just a boolean value.
We don't really have way of saying "sync the attribute once and then use the property" and I don't know that adding said logic is even a good idea...
defaultMuted
is the spec'd solution for this. It sets the initial muted value by reflecting the muted
attribute, which can then be controlled using the muted
property.
We don't support many attributes that aren't actually DOM attributes, but we do have defaultValue
so I think there's a good argument for mirroring that API here.
we want to get away from that special-cased behavior, since it's caused a number of problems.
yeah the controlling behavior ends up causing so many headaches i wouldn't want to do it again, though i agree that it's the right behavior generally.
We don't support many attributes that aren't actually DOM attributes, but we do have defaultValue so I think there's a good argument for mirroring that API here.
I like that idea, tho It's always a slippery slope, what would the SSR behavior if someone specifies defaultMuted
but no muted
, ? I suppose we already handle this with value and checked...
I like that idea, tho It's always a slippery slope, what would the SSR behavior if someone specifies defaultMuted but no muted, ? I suppose we already handle this with value and checked...
Yeah, I imagine it would behavior just like defaultValue
does for SSR, by rendering the value
attribute with the provided value.
ya my concern is just that most of the value/defaultValue is special cased through the codebase sort of assuming the pattern will be used just for inputs. I should probably go see how it works tho before worrying about that...
My assumption is that the one use case for defaultMuted
is to handle the situation where the muted
attribute should be present when the video is first rendered. Since it has no dynamic behavior, per the spec, I think just defining it as a boolean attribute that must set the property (easy to do with PropertyInfoRecord
) would be good enough? I hope at least 😅
It could be just as easy as adding it to this list:
`const { Component } = React
const { render } = ReactDOM
class App extends Component {
render () {
return (
src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4"
autoPlay
video />
)
}
}
render(
If you run this code there is a video playing automatically with audio.
I have used video instead of muted attribute.
muted
is an extremely important attribute for background videos. _Please_ expose it to the browser. 🙏
In the meantime, if you need to autoplay background videos, try this:
import * as React from 'react';
import { Component } from 'react';
export class VideoComponent extends Component {
videoContainer: HTMLDivElement;
componentDidMount() {
const video = document.createElement('video');
video.autoplay = true;
video.loop = true;
video.muted = true; // fixes autoplay in chrome
video.setAttribute('playsinline', 'true'); // fixes autoplay in webkit (ie. mobile safari)
const source = document.createElement('source');
source.src = '/path/to/your/video.mp4';
source.type = 'video/mp4';
video.appendChild(source);
this.videoContainer.appendChild(video);
}
render() {
return (
<div ref={(ref) => { this.videoContainer = ref; }} />
);
}
}
Thank you for your consideration.
Indeed, ended up doing dangerouslySetHTML because React doesn't accept muted.
https://www.npmjs.com/package/react-html5video this component also seems to expose muted
And still this issue persisted
While muted still doesn't show up as an attribute on the video element. Simply adding the playsInline makes the video play on iOS/Safari and Chrome.
<video className={s.video} src={video.url} autoPlay={video.autoplay} playsInline muted={video.mute ? 1 : null} loop={video.loop} />
As commented in 6544 this supposedly doesn't work in Chrome Android
I feel like this is a source of bugs and therefore not really a feature request. Is there any plan to work on this? None of the workarounds feel nice to me.
Agree with @adjohu, this is a bug, not a feature request. Video elements will not autoplay on in mobile Safari without the muted
attribute. How hard can it be to just guarantee the attribute? I can use dangerouslySetInnerHTML
for the video element, but I also need a ref to it, so that doesn't work.
Almost two years and there still is no good way of doing this :/
@joshverd is there ANY way of doing it? Haha. I can't find anything about a video element in react, with a muted attribute, and also with a ref. It's like I'm on Mars, I can't believe this is such an uncommon requirement 😬
@keithpickering
Actually, I got something working. It's really hack-ish but it works.
Basically, you want to save the element's 'ref'
<video ref={ref => this.videoRef = ref} src="link/to/video.mp4" />
Then you have to set the element's muted property to true and play the video all from within JS.
startVideoPlayback() {
// Muting the video
this.videoRef.muted = true;
// Playing the video
this.videoRef.play();
}
This is the only way I can get Chrome to "autoplay" video, but you still have to call the 'startVideoPlayback' function. Anything else and it gets paused by Chrome's autoplay detection.
Wow, that .play()
works on mobile? I can never keep track of this dumb spec lol. That's an interesting approach, thanks!
Still experiencing this issue in React 16.11.0, muted attribute not showing up on the video element even though explicitly defined. Did I miss something?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution.
Still a valid issue
updated a fiddle to reflect React 16 since the OP was still using 15.
still valid.
If you would like to have muted
attribute present in HTML you can use this component (hook version) as well:
import { useRef, useEffect } from 'react'
const Player = () => {
const videoRef = useRef(null)
useEffect(() => {
const { current: videoElement } = videoRef
videoElement.setAttribute('muted', '')
}, [])
return (
<video
src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4"
ref={videoRef}
autoPlay
playsInline
muted
/>
)
}
export default Player
Regarding autoplay:
Isn't it related with that: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
When you are using e.g. jsfiddle.net to test your code snippet, everything is rendered inside iframe
there and the default behavior for e.g. Chrome is to block autoplay of such videos. If you would like the autoplay to work, you can add something like this to your local application:
<iframe src="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4" allow="autoplay" />
@mar753 - that's an elegant solution using hooks but it doesn't answer the question of why this prop isn't being passed, despite being a known bug for years.
Any update on this? Seems like a simple fix.
@gaearon sorry to borther you, but someone should handle this problem since it's really annoying.
People who are just trying to autoplay muted
Thank you for your blog @boltcoder, but to me using dangerouslySetInnerHtml
was not the solution I was expecting. I am expecting my muted
attribute to be reflected inside the dom, I think browsers also expect that.
From Google documentation about Autoplay policy changes (2017-09):
One cool way to engage users is about using muted autoplay and let them chose to unmute (see code snippet below).
Some websites already do this effectively, including Facebook, Instagram, Twitter, and YouTube.
<video id="video" muted autoplay>
<button id="unmuteButton"></button>
<script>
unmuteButton.addEventListener('click', function() {
video.muted = false;
});
</script>
The example speaks by itself: chrome is expecting the dom to contain the muted
attribute, just like it's expecting it to contain the autoplay
attribute.
Ofcourse it's not the right solution. But that's what I had to do to make it work in React. I'm just helping people out on tight deadlines to circumvent the limitations while react fixes (or doesn't fix the attribute to dom guarantee issue).
3 years later and facing the same issue here.
Still a bug, can't believe I was just forced to use dangerouslySetHTML
to get around this…
Still a bug, can't believe I was just forced to use
dangerouslySetHTML
to get around this…
you dont need to use dangerouslySetHTML, try this: https://github.com/facebook/react/issues/6544#issuecomment-705702546
What is the latest proposal in this thread? I think the issue has stalled because there was no single proposal that people could get behind. It would help to flesh out what exactly the behavior should be with regards to whether it should be setting an attribute or a property, and whether it should be controlled or uncontrolled. Once we have a proposal, it's easier for someone to make a PR.
proposal: the muted attribute when passed as a prop to a video component with a boolean value will be added to the dom.
What is your plan for defaultMuted
vs muted
, controlled vs uncontrolled, server rendering?
incremental progress :)
Sorry, I appreciate your intent but this is not helpful and does not move the thread forward. This thread has stalled because it doesn't have a concrete proposal. If you don't have a concrete technical proposal (what you posted is vague), let's wait for somebody to post theirs. Concretely, there were concerns in https://github.com/facebook/react/issues/10389#issuecomment-378677272 that need to be addressed.
From the React16 intro:
In the past, React used to ignore unknown DOM attributes. If you wrote JSX with an attribute that React doesn’t recognize, React would just skip it. For example, this:
// Your code:
<div mycustomattribute="something" />
would render an empty div to the DOM with React 15:
// React 15 output:
<div />
In React 16, we are making a change. Now, any unknown attributes will end up in the DOM:
// React 16 output:
<div mycustomattribute="something" />
So does React omit 'muted' because it is known? Why does React needs to take into account each scenario including SSR / defaultMuted when we have an existing convention that developers should be able to follow?
React, in general, needs to take every scenario into account. :-) It doesn't do that for arbitrary attributes that don't have special behavior because... they don't have special behavior. In this case, there are two different backing properties, and we need make sure that the behavior makes sense (i.e. it follows React's controlled/uncontrolled model like checked
and value
do).
In React, generally saying, JSX attributes specify the current value rather than the initial one.
<input value={myState} />
means that if myState
gets set by some other part of the code, the input value will reflect it.
So if muted={true}
meant "initially muted" it would not be consistent with how other similar JSX attributes work.
Instead, to specify the initial behavior, we use properties starting with default
: defaultValue
, defaultChecked
. This is because DOM properties that mirror the attribute are called with this convention.
So it seems like what we really want here is support for defaultMuted
?
Works for me and helps devs conform to mdn's recomendations here.
I created a PR that fixes this issue:
https://github.com/facebook/react/pull/20087
note, previous PR won't add defaultMuted, instead it put into the DOM the muted property and fixes the unit testing failing with
Most helpful comment
muted
is an extremely important attribute for background videos. _Please_ expose it to the browser. 🙏In the meantime, if you need to autoplay background videos, try this:
Thank you for your consideration.