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;
  position: absolute;
  left: 150px;
  display: none;
}

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

JavaScript

const animation =
    new Animation(new KeyframeEffect(
      target, 
      [
        { opacity: 0, display: "none" },
        { opacity: 1, display: "block" },
      ], {
        delay: 1000,
        endDelay: 1000,
        duration: 1000
      }
    ));

  animation.effect.updateTiming({
    fill: 'both'
  });

  animation.onfinish = () => {
    animation.commitStyles();
    playing.innerText = 'false'
    playing.style.cssText += '--color:red'
  };
  
  target.style.display = "block";
  animation.reverse();
  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) => {
    playing.innerText = 'true'
    playing.style.cssText += '--color: green'

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