'Why `muted` attribute on video tag is ignored in React?

Well, as counter-intuitive as it sounds, muted tag is somehow ignored; check out the snippet below, first one is rendered with react, the second one regular html; inspect them with your dev tools, and you see the react on doesn't have muted attribute; I already tried muted={true}, muted="true" but non is working.

function VideoPreview() {
  return (
    <div className="videopreview-container">
      React tag:
      <video
        className="videopreview-container_video"
        width="320"
        height="240"
        controls
        autoPlay
        muted
      >
        <source src="https://raw.githubusercontent.com/rpsthecoder/h/gh-pages/OSRO-animation.mp4" type="video/mp4" />
        Your browser does not support the video tag.
      </video>
    </div>
  );
}

ReactDOM.render(<VideoPreview />, root)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


<div id="root"></div>


<hr/>
Regular html:
<video
  width="320"
  height="240"
  controls
  autoplay
  muted
>
  <source src="https://raw.githubusercontent.com/rpsthecoder/h/gh-pages/OSRO-animation.mp4" type="video/mp4" />
  Your browser does not support the video tag.
</video>


Solution 1:[1]

As mentioned by @FluidSense it is an open bug since forever.

I could achieve it like this:

import React, { useRef, useEffect } from "react";

export default function Video({ src, isMuted }) {
    const refVideo = useRef(null);

    useEffect(() => {
        if (!refVideo.current) {
            return;
        }

        if (isMuted) {
            //open bug since 2017 that you cannot set muted in video element https://github.com/facebook/react/issues/10389
            refVideo.current.defaultMuted = true;
            refVideo.current.muted = true;
        }

        refVideo.current.srcObject = src;
    }, [src]);

    return (
            <video
                ref={refVideo}
                autoPlay
                playsInline //FIX iOS black screen
            />
    );
}

Solution 2:[2]

Here is how I dealt with it using dangerouslySetInnerHTML:

import React, { Component } from "react";

export default class VideoComponent extends Component {
  state = {
    videoStr: "",
  };
  componentDidMount() {
    const { src } = this.props;
    const videoStr = `
        <video autoplay loop muted>
            <source src=${src} type="video/mp4" />
        </video>
    `;
    this.setState({ videoStr });
  }
  render() {
    return (
      <div
        className={this.props.className}
        dangerouslySetInnerHTML={{ __html: this.state.videoStr }}
      />
    );
  }
}

Solution 3:[3]

I would also note that some browsers like Chrome might have a limit for the file size a video can be. I was running my own videos on my website and when I inspected the page and looked under Sources I did not find the video I had used and been looking for. This forced me to investigate further. I realized the video that I was running was about 10.4mb. It was large relative to the usual payload of a website so I lowered the size to around 5mb and the video appeared on my site.

Some other information about my steps to finding a solutions was that I was using my localhost to run my React app. I also ran my React app on Safari which surprisingly displayed my video even when the size was 10.4mb. I'm guessing that browsers have different criteria for video sizes.

Solution 4:[4]

muted works if you type it as muted="true". Using the string true sends the attribute to the DOM now

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 CodingYourLife
Solution 2 Mhmdrz_A
Solution 3 Cap Lee
Solution 4 itwasmattgregg