'keyframes are not animating the transforms property properly

So, I am making an animated toggle component in react js, and to achieve that I am using keyframes to animate the properties, but it is not working as expected.

Here is the slow-motion video of the animation I want to achieve. video link

Here is the video of what my animation actually does video link

As you can see that there is a glitch, when it unchecks, this is because the dot in the center scales to 0 before the border width has fully occupied the space

Here is the link for the codesandbox

Here is the code for the CSS

*,
*::after,
*::before {
  box-sizing: border-box;
}

.App {
  font-family: sans-serif;
  text-align: center;
}

.payment-container {
  position: absolute;
  right: 4%;
  top: 12%;
  width: 300px;
  /* width: 25%; */
  height: 80%;
  border-radius: 4px;
  background-color: #ececec;
  /* background-color: rgba(209, 209, 209, 0.5); */
  padding: 1rem;
}

.payment-container h2 {
  margin-block: 0;
  font-family: "Poppins", sans-serif;
}

.payment-method {
  display: flex;
  flex-direction: column;
}

.payment-container .subtitle {
  color: rgb(107, 107, 107);
  font-family: "Poppins", sans-serif;
  font-weight: 500;
  font-size: 15px;
}

.radio_button_input {
  opacity: 0;
  position: absolute;
  padding: 0;
  z-index: 1;
  margin-top: 6px;
  cursor: pointer;
  transform: scale(1.25);
}

.circle {
  position: relative;
  display: inline-block;
  width: 20px;
  height: 20px;
  vertical-align: middle;
  background-color: inherit;
  color: #017b5f;

  border: 2px solid #b9b9b9;
  border-radius: 24px;
  opacity: 1;
}

.circle::after {
  content: "";
  display: block;
  position: relative;
  top: 13%;
  left: 13%;
  width: 12px;
  z-index: 5;
  height: 12px;
  background-color: #727171;
  border-radius: 12px;
}

.radio_button_input:checked + .circle::after {
  background-color: #01a982;
}

.radio_button_input:not(:checked) + .circle::after {
  background-color: #b9b9b9;
  animation: borderDot 2s linear;

  animation-fill-mode: forwards;
}

@keyframes borderDot {
  0% {
    transform: scale(1);
  }
  24% {
    transform: scale(1.35);
  }
  25% {
    transform: scale(0);
  }
  100% {
    transform: scale(0);
  }
}

.radio_button_input:checked + .circle {
  border-color: #01a982;
  transition: all 1s;
}

.circle {
  transform: scale(0.85);
}

.radio_button_input:not(:checked) + .circle {
  animation: borderWidths 2s linear;
  animation-fill-mode: forwards;
}

@keyframes borderWidths {
  0% {
    transform: scale(0.85);
    border-width: 2px;
  }
  24% {
    border-width: 2px;
  }
  25% {
    transform: scale(0.75);
    border-width: 10px;
  }
  50% {
    transform: scale(0.85);
    border-width: 2px;
  }
  75% {
  }
  100% {
    transform: scale(0.85);
    border-width: 2px;
  }
}

.flex-container {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 0.5rem;
}

Here is the js code

import { useState } from "react";
import "./styles.css";
import { CreditCard } from "react-feather";

export default function App() {
  const [method, setMethod] = useState({
    pay_method: "card"
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setMethod({
      pay_method: name
    });
  };
  return (
    <div className="App">
      <div className="payment-container">
        <h2>Payment Info.</h2>
        <div className="payment-method">
          <span className="subtitle">Payment Method:</span>
          <div className="flex-container">
            <div>
              <input
                type="radio"
                className="radio_button_input"
                id="card_radio"
                name="card"
                checked={method?.pay_method == "card"}
                onChange={handleChange}
              />
              <span className="circle"></span>
            </div>
            <CreditCard size={"18px"} />
            <span>Credit Card</span>
          </div>
          <div className="flex-container">
            <input
              type="radio"
              className="radio_button_input"
              id="paypal_radio"
              name="paypal"
              checked={method?.pay_method == "paypal"}
              onChange={handleChange}
            />
            <span className="circle"></span>
            <svg
              width={"18px"}
              xmlns="http://www.w3.org/2000/svg"
              viewBox="0 0 384 512"
            >
              <path d="M111.4 295.9c-3.5 19.2-17.4 108.7-21.5 134-.3 1.8-1 2.5-3 2.5H12.3c-7.6 0-13.1-6.6-12.1-13.9L58.8 46.6c1.5-9.6 10.1-16.9 20-16.9 152.3 0 165.1-3.7 204 11.4 60.1 23.3 65.6 79.5 44 140.3-21.5 62.6-72.5 89.5-140.1 90.3-43.4.7-69.5-7-75.3 24.2zM357.1 152c-1.8-1.3-2.5-1.8-3 1.3-2 11.4-5.1 22.5-8.8 33.6-39.9 113.8-150.5 103.9-204.5 103.9-6.1 0-10.1 3.3-10.9 9.4-22.6 140.4-27.1 169.7-27.1 169.7-1 7.1 3.5 12.9 10.6 12.9h63.5c8.6 0 15.7-6.3 17.4-14.9.7-5.4-1.1 6.1 14.4-91.3 4.6-22 14.3-19.7 29.3-19.7 71 0 126.4-28.8 142.9-112.3 6.5-34.8 4.6-71.4-23.8-92.6z" />
            </svg>
            <span className="radio-button-label">Paypal</span>
          </div>
        </div>
      </div>
    </div>
  );
}



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source