JSFiddle - React, Tailwind, and code Playground

by thormeier

HTML

<no-autoplay-gif
    src="https://64.media.tumblr.com/bc15a95b75b02d89de1ad0eda0066940/tumblr_mmb12d6EuL1r3gb3zo1_250.gif"
    alt="Llama and cat"
/>

JavaScript

const noAutoplayGifTemplate = document.createElement('template')
noAutoplayGifTemplate.innerHTML = `
<style>
.no-autoplay-gif {
  --size: 30px;
  cursor: pointer;
  position: relative;
}

.no-autoplay-gif .gif-label {
  border: 2px solid #000;
  background-color: #fff;
  border-radius: 100%;
  width: var(--size);
  height: var(--size);
  text-align: center;
  font: bold calc(var(--size) * 0.4)/var(--size) sans-serif;
  position: absolute;
  top: calc(50% - var(--size) / 2);
  left: calc(50% - var(--size) / 2);
}

.no-autoplay-gif .hidden {
  display: none;
}
</style>
<div class="no-autoplay-gif">
  <canvas></canvas>
  <span class="gif-label" aria-hidden="true">GIF</span>
  <img class="hidden">
</div>
`

class NoAutoplayGif extends HTMLElement {
  constructor() {
    super()

    // Attach the shadow DOM
    this._shadowRoot = this.attachShadow({ mode: 'open' })

    // Add the template from above
    this._shadowRoot.appendChild(
      noAutoplayGifTemplate.content.cloneNode(true)
    )

    // We'll need these later on.
    this.canvas = this._shadowRoot.querySelector('canvas')
    this.img = this._shadowRoot.querySelector('img')
    this.label = this._shadowRoot.querySelector('.gif-label')
    this.container = this._shadowRoot.querySelector('.no-autoplay-gif')

    // Make the entire thing clickable
    this._shadowRoot.querySelector('.no-autoplay-gif').addEventListener('click', () => {
      this.toggleImage()
    })
  }

  loadImage() {
    const src = this.getAttribute('src')
    const alt = this.getAttribute('alt')

    if (!src) {
      console.warn('A source gif must be given')
      return
    }

    if (!src.endsWith('.gif')) {
      console.warn('Provided src is not a .gif')
      return
    }

    this.img.onload = event => {
      const width = event.currentTarget.width
      const height = event.currentTarget.height

      // Set width and height of the entire thing
      this.canvas.setAttribute('width', width)
     ...