Skip to content
Advertisement

tag does not work in Safari when using DOMParser

When using DOMParser, <video> tag is not working in Safari, its preview is rendered but without controls and without the ability to play:

const parser = new DOMParser()
const parsed = parser.parseFromString(
  document.querySelector('video').outerHTML, 
  'text/html'
)
document.body.appendChild(parsed.querySelector('body').childNodes[0])
<video
  width="250"
  controls
  playsinline
  src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4#t=0.001"
></video>

The code above works as expected in Chrome:

enter image description here

But Safari renders this (both macOS and iOS):

enter image description here

There are no controls and it’s impossible to play the second video which was produced by DOMParser.

Is that some kind of security feature or a bug? Is there any workaround for this behavior?

Advertisement

Answer

This is a Bug

Here’s a link to the webkit bug ticket.

  • comment #6 (2021-03-04 22:50:29 PST):

    […] media element not initialize its UA shadow root when it’s created inside a document without a browsing context. The fix is to initialize the media element controls once it’s inserted into a document with a browsing context.

  • comment #12 (2022-08-02 11:16:50 PDT): Pull request: https://github.com/WebKit/WebKit/pull/2955

  • comment #13 (2022-08-08 11:47:08 PDT): Committed 253225@main (f331cc98c1de): https://commits.webkit.org/253225@main Reviewed commits have been landed. Closing PR #2955 and removing active labels.

Here’s a Workaround

// keep doing what you were doing:
const parser = new DOMParser()
const parsed = parser.parseFromString(
  document.querySelector('video').outerHTML, 
  'text/html'
);
const child = document.body.appendChild(parsed.querySelector('body').childNodes[0]);

// but then force the media elements to reload afterward:
[child].concat(Array.from(child.querySelectorAll("video, audio")))
  .forEach(e => e.outerHTML = e.outerHTML);

There are other workarounds like the cloneNode one that @Tibic4 suggested, but I think this one is nice in that you can still keep using DOMParser for most of the work.

Once the webkit fix gets deployed you won’t need the workaround for any of the Safari versions where the fix gets applied. Hopefully it gets reasonably backported.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement