JSFiddle - React, Tailwind, and code Playground

by Glenn Marks

HTML

<div id=target></div>
<button id=show type=button>Show</button>
<button id=hide type=button>Hide</button>
<p><strong>Reversed:</strong> <span id=reversed>false</span></p>
<p><strong>Playing:</strong> <span id=playing>false</span></p>
<pre><code>
    <strong>As you can see, the opacity flickers</strong>
-----------------------------------------------------------------------
    <strong>Note for Chrome:</strong> When animation is reversed,
    an external event is required to update the finished state,
    eg. pointer move or key down event.
    There is a bug filed (<a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1141935">star it</a>)
    <!-- This is actually where i got most of this code from 😁 -->
</code></pre>

<p><b>Proposal</b></p>
<pre><code>
    <span style=color:green>// Proposal usage example</span>
    animation.onstart = () => {
	var isReverse = animation.playbackrate === -1;
	target.style.opacity = 
            isReverse
                ? "1"
                : "0";

        playing.innerText = 'true'
        playing.style.cssText += '--color: green'

        reversed.innerText = isReverse.toString();
        reversed.style.cssText += isReverse
            ? '--color: green'
            : '--color: red';
    };
</code></pre>

CSS

div {
  width: 100px;
  height: 100px;
  background-color: black;
}

span {
  color: var(--color, red);
}

JavaScript

const sustainOpacity = (direction) => {
    target.style.opacity = direction === "forward" ?
      "1" :
      "0";
  }

  const animation =
    target.animate({
      opacity: [0, 1]
    }, {
      delay: 1000,
      endDelay: 1000,
      duration: 1000
    });

  animation.onfinish = () => {
    sustainOpacity(target.dataset.direction);

    playing.innerText = 'false'
    playing.style.cssText += '--color:red'
  };

  animation.finish();

  show.onclick = () => {
    if (animation.playbackRate === 1) {
      animation.play();
    } else {
      animation.reverse();
    }
    animationStart(false); // <= Drop this under new proposal
  }

  hide.onclick = () => {
    if (animation.playbackRate === 1) {
      animation.reverse();
    } else {
      animation.play();
    }
    animationStart(true); // <= Drop this under new proposal
  }

  // DROP THIS AS WELL
  const animationStart = (isReverse) => {
    target.dataset.direction = isReverse ?
      "reverse" :
      "forward";

    target.style.opacity =
      target.dataset.direction === "forward" ?
      "0" :
      "1";

    playing.innerText = 'true'
    playing.style.cssText += '--color: green'

    reversed.innerText = isReverse.toString();
    reversed.style.cssText += isReverse ?
      '--color: green' :
      '--color: red';
  }