<div class="theme-switcher__container">
   <div class="theme-switcher flex mb-4 sm--mb-0 text-tiny">
      <div class="theme-switcher__option flex flex-align-center mr-2">
         <input class="theme-switcher__input" type="radio" id="theme-light" name="theme-selector" value="light" \>
         <label class="theme-switcher__label inline-block px-3 py-1 capitalize text-action-base border-radius-small" for="theme-light">
            Light
         </label>

         <svg class="theme-switcher__icon theme-switcher__icon--sun" width="50" height="50" viewBox="-50 -50 100 100">
            <defs>
               <polygon id="sun-ray" points="0,0 -20,0 0,-50 20,0" fill="#ff851b" />
            </defs>

            <g class="svg-sun-rays">
               <use href="#sun-ray" />
               <use href="#sun-ray" transform="rotate(45)" />
               <use href="#sun-ray" transform="rotate(90)" />
               <use href="#sun-ray" transform="rotate(135)" />
               <use href="#sun-ray" transform="rotate(180)" />
               <use href="#sun-ray" transform="rotate(225)" />
               <use href="#sun-ray" transform="rotate(270)" />
               <use href="#sun-ray" transform="rotate(315)" />
            </g>

            <circle class="svg-sun" cy="0" cx="0" r="30" fill="#ff851b" stroke-width="5px" stroke="white" />
         </svg>
      </div>

      <div class="theme-switcher__option flex flex-align-center mr-2">
         <input class="theme-switcher__input" type="radio" id="theme-dark" name="theme-selector" value="dark" \>
         <label class="theme-switcher__label inline-block px-3 py-1 capitalize text-action-base border-radius-small" for="theme-dark">
            Dark
         </label>

         <svg class="theme-switcher__icon theme-switcher__icon--moon" width="50" height="50" viewBox="-50 -50 100 100">
            <circle cy="0" cx="0" r="45" fill="#7fdbff" />
            <circle class="svg-moon-ellipse" cy="0" cx="-35" r="45" fill="white" />
         </svg>
      </div>
   </div>
</div>
.theme-switcher__container {
   display: flex;
   width: 100vw;
   height: 100vh;
   align-items: center;
   justify-content: center;
}

.theme-switcher {
   display: flex;
   padding: 1rem;
}

.theme-switcher__option {
   position: relative;
   display: flex;
   padding: 0.25rem;
   margin: 0 0.5rem;
   min-width: 110px;
   align-items: center;
   justify-content: space-between;

   border: 2px solid black;
   border-radius: 5px;

   overflow: hidden;
}

.theme-switcher__input {
   opacity: 0;
   position: fixed;
   width: 0;

   &:checked + .theme-switcher__label {
      font-weight: 700;
      text-decoration: underline;
   }

   &:focus + .theme-switcher__label {
      // outline: 2px solid red;
      // outline-offset: -3px;
   }
}

.theme-switcher__label {
   position: absolute;
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;

   display: flex;
   padding: 0.25rem 0.5rem;
   margin-right: 5px;
   align-items: center;

   &:hover,
   &:focus {
      cursor: pointer;
   }
}

.theme-switcher__icon {
   margin-left: auto;
}

.svg-sun-rays {
   transform-origin: 50%;
}

.svg-moon-ellipse {
   transform-origin: 0% 50%;
}
View Compiled
const animation = {
   duration: 0.5,
   black: "black",
   white: "white",
   dark: "#060f94",
   light: "#fcf4a3"
};

(function () {
   const themeRadios = document.getElementsByClassName("theme-switcher__input");

   function addEventListeners() {
      for (var i = 0, max = themeRadios.length; i < max; i++) {
         themeRadios[i].onclick = function (el) {
            const selectedTheme = el["srcElement"]["defaultValue"];
            setTheme(selectedTheme);
         };
      }
   }

   function setTheme(theme) {
      const themeRadio = document.getElementById(`theme-${theme}`),
         themeSwitch = document.getElementsByClassName("theme-switcher")[0],
         body = document.getElementsByTagName("BODY")[0],
         lightTheme = theme === "light";
      themeRadio.checked = true;
      localStorage.setItem("theme", theme);

      themeSwitch.classList.add(
         lightTheme ? "theme-switcher--light" : "theme-switcher--dark"
      );
      body.classList.add(lightTheme ? "theme-light" : "theme-dark");

      themeSwitch.classList.remove(
         lightTheme ? "theme-switcher--dark" : "theme-switcher--light"
      );
      body.classList.remove(lightTheme ? "theme-dark" : "theme-light");

      const tl = gsap.timeline({ defaults: { duration: animation.duration } });

      tl.to(
         "body",
         {
            backgroundColor: lightTheme ? animation.light : animation.dark,
            color: lightTheme ? animation.black : animation.white
         },
         0
      );

      tl.to(
         ".theme-switcher__option",
         {
            borderColor: lightTheme ? animation.black : animation.white
         },
         0
      );

      tl.to(
         ".svg-sun",
         {
            stroke: lightTheme ? animation.light : animation.dark
         },
         0
      );

      tl.to(
         ".svg-moon-ellipse",
         {
            fill: lightTheme ? animation.light : animation.dark
         },
         0
      );

      tl.to(
         ".theme-switcher__icon--moon",
         {
            yPercent: lightTheme ? 115 : 0
         },
         0
      );

      tl.to(
         ".theme-switcher__icon--sun",
         {
            yPercent: lightTheme ? 0 : 115
         },
         0
      );

      tl.to(
         ".svg-sun-rays",
         {
            scale: lightTheme ? 1 : 0
         },
         animation.duration
      );

      tl.to(
         ".svg-moon-ellipse",
         {
            scale: lightTheme ? 0 : 1
         },
         animation.duration
      );
   }

   addEventListeners();
})();
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://unpkg.co/gsap@3/dist/gsap.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js