Skip to content
Advertisement

Why is this keyframe animation not applied when using styled-jsx?

I tried adding the animation on a separate line without any condition, but than the transition is not applied. I also tried backticks instead of double quotes for the animation property without success. How to have the both the animation applied when clicked is false and play the transition for the radius when clicked is true?

import { useState } from "react";

export default function Home() {
  const [clicked, setClicked] = useState(false);

  return (
    <>
      <main>
        <svg onClick={() => setClicked((c) => !c)}>
            <circle cx="50%" cy="40%" stroke="black" strokeWidth={2} fill="gray" />
        </svg>
      </main>

      <style jsx>{`
        svg {
          width: 100%;
          height: 100%;
        }

        circle {
          r: ${clicked ? "10%" : "5%"};
          animation: ${clicked ? "none" : "bounce 2s infinite"};
          transition: r 0.8s ease-in-out;
        }

        @keyframes bounce {
          0% {
            r: 5%;
          }
          50% {
            r: 6%;
          }
          100% {
            r: 5%;
          }
        }
      `}</style>
    </>
  );
}

Advertisement

Answer

This has to do with how styled-jsx applies their css rules.
each <style jsx> tag will be transpiled by babel into a piece of js code that will generate and keep track of an actual <style type="txt/css"/> tag in the html.

That tag will contain a unique ID, if you inspect that tag it will look something like this:

<style type="text/css" data-styled-jsx="">
      svg.jsx-1097321267 {
        width: 100%;
        height: 100%;
      }
      circle.jsx-1097321267 {
        r: 5%;
        -webkit-animation: bounce 2s infinite;
        animation: bounce 2s infinite;
        -webkit-transition: r 0.8s ease-in-out;
        transition: r 0.8s ease-in-out;
      }
      @-webkit-keyframes bounce-jsx-1097321267 {
        0% {
          r: 5%;
        }
        50% {
          r: 6%;
        }
        100% {
          r: 5%;
        }
      }
      @keyframes bounce-jsx-1097321267 {
        0% {
          r: 5%;
        }
        50% {
          r: 6%;
        }
        100% {
          r: 5%;
        }
      }
    </style>

Notice how the animation is also generated with the same ID. bounce-jsx-1097321267.
Any static references/classes in the styles-jsx tag also get this id. This is all done through babel at compile time. The resulting js code will do all that referencing for you.

A problem arises when a assigning the css code dynamically. It seems, that the ${clicked ? "none" : "bounce 2s infinite"}; rule fails to add the generated id to bounce animation name. This might be by design or might be a bug, or simply a limitation in styled-jsx. IDK.

You have a couple of options to work around this, probably the easiest way is the make the css style static, and add a class when new styling should be applied.

IE

 circle {
          r: 5%;
          animation: bounce 2s infinite;
          transition: r 0.8s ease-in-out;
        }

        .is-clicked {
          animation: none;
          r: 10%;
        }

and applying a class to circle like className={clicked && "is-clicked"} , that way the animation name will be contain an id, and any rule using that animation will also receive the same id.

code sandbox for reference

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