Close Menu

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    How to make Solar System Planet Picker Animation using HTML CSS & JavaScript

    10 April 2026

    How to make Glowing Tab Navigation using HTML CSS & JavaScript

    9 April 2026

    How to create Nike Shoes Animation using HTML CSS and JS

    8 April 2026
    Facebook X (Twitter) Instagram YouTube Telegram Threads
    Coding StellaCoding Stella
    • Home
    • Blog
    • HTML & CSS
      • Login Form
    • JavaScript
    • Hire us!
    Coding StellaCoding Stella
    Home - JavaScript - How to make Solar System Planet Picker Animation using HTML CSS & JavaScript
    JavaScript

    How to make Solar System Planet Picker Animation using HTML CSS & JavaScript

    Coding StellaBy Coding Stella10 April 2026No Comments9 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Reddit Email WhatsApp Copy Link

    Let’s create a Solar System Planet Picker Animation using HTML, CSS, and JavaScript. This project builds an interactive UI where users can switch between planets with smooth animations, dynamic data updates, and a rotating navigation system – perfect for making your UI feel futuristic and engaging.

    We’ll use:

    • HTML to structure each planet section with title, description, details (tilt, gravity, hours), and images, along with an SVG-based curved navigation for selecting planets.
    • CSS to design the full-screen layout, position elements using grid, and create smooth animations like text reveal, fading images, and transitions when switching planets.
    • JavaScript to handle planet switching, update active states, animate values dynamically, rotate the navigation based on selection, and add interactive click events.

    This project is a great way to understand advanced UI animations, DOM manipulation, and smooth transitions while building a visually impressive solar system experience. 🚀

    HTML :

    The HTML defines the structure of the app with multiple .planet sections (each having title, description, details, and image) and an SVG curved navigation bar listing planet names; each planet has data-planet and data-detail attributes used by JS to identify and update content, with one planet active by default, making it a dynamic solar system selector UI.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Solar System Planet Picker Keyframe Animation | @coding.stella</title>
      <link rel="stylesheet" href="https://public.codepenassets.com/css/normalize-5.0.0.min.css">
      <link rel='stylesheet' href='https://unpkg.com/splitting@1.0.6/dist/splitting.css'>
      <link rel="stylesheet" href="./style.css">
    
    </head>
    
    <body>
      <div id="app" data-current-planet="mercury">
    
        <nav class="planet-nav">
          <svg viewBox="0 20 400 400" xmlns="http://www.w3.org/2000/svg">
    
            <!--       <defs> -->
            <path id="navPath" d="M10,200 C30,-28 370,-28 390,200" fill="none" />
            <!--       </defs> -->
    
            <text>
              <textPath href="#navPath" startOffset="0" font-size="10">
                <tspan>Mercury</tspan>
                <tspan>Venus</tspan>
                <tspan>Earth</tspan>
                <tspan>Mars</tspan>
                <tspan>Jupiter</tspan>
                <tspan>Saturn</tspan>
                <tspan>Uranus</tspan>
                <tspan>Neptune</tspan>
              </textPath>
            </text>
    
          </svg>
        </nav>
    
        <div class="planet" data-planet="mercury" data-active>
          <div class="planet-title">
            <h1>Mercury</h1>
            <p class="planet-description">Tiny and close to the sun.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              3.13
            </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              0.9
            </div>
            <div class="detail" data-detail="hours">
              10
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/1_mercury.jpg" />
          </figure>
        </div>
    
        <div class="planet" data-planet="venus">
          <div class="planet-title">
            <h1>Venus</h1>
            <p class="planet-description">A planet of razors and tennis players.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              4.13
            </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              0.2
            </div>
            <div class="detail" data-detail="hours">
              20
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/2_venus.jpg" />
          </figure>
        </div>
    
        <div class="planet" data-planet="earth">
          <div class="planet-title">
            <h1>Earth</h1>
            <p class="planet-description">Voted best planet in the Solar System by all organisms.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              5.13
            </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              7.3
            </div>
            <div class="detail" data-detail="hours">
              30
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/3_earth.jpg" />
          </figure>
        </div>
    
        <div class="planet" data-planet="mars">
          <div class="planet-title">
            <h1>Mars</h1>
            <p class="planet-description">Future Site of Elon Musk's AirBnB.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              6.13
            </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              1.1
            </div>
            <div class="detail" data-detail="hours">
              40
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/4_mars.jpg" />
          </figure>
        </div>
    
        <div class="planet" data-planet="jupiter">
          <div class="planet-title">
            <h1>Jupiter</h1>
            <p class="planet-description">Twice as massive as the other planets combined.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              11.13
            </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              1.8
            </div>
            <div class="detail" data-detail="hours">
              50
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/5_jupiter.jpg" />
          </figure>
        </div>
    
        <div class="planet" data-planet="saturn">
          <div class="planet-title">
            <h1>Saturn</h1>
            <p class="planet-description">This planet sponsored by Zales.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              9.13
            </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              7.3
            </div>
            <div class="detail" data-detail="hours">
              60
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/6_saturn.jpg" />
          </figure>
        </div>
    
        <div class="planet" data-planet="uranus">
          <div class="planet-title">
            <h1>Uranus</h1>
            <p class="planet-description">Hey, stop laughing. It's not funny.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              11.13
            </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              1.8
            </div>
            <div class="detail" data-detail="hours">
              50
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/7_uranus.jpg" />
          </figure>
        </div>
    
    
        <div class="planet" data-planet="neptune">
          <div class="planet-title">
            <h1>Neptune</h1>
            <p class="planet-description">A planet for pirates; just narrowly made the cut when scientists decided nine
              planets was too many.</p>
          </div>
    
          <div class="planet-details">
            <div class="detail" data-detail="tilt" data-postfix="°">
              31.03 </div>
            <div class="detail" data-detail="gravity" data-postfix="𝗑">
              8.9 </div>
            <div class="detail" data-detail="hours">
              10
            </div>
          </div>
    
          <figure class="planet-figure">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1188/8_neptune.jpg" />
          </figure>
        </div>
      </div>
      <script src='https://unpkg.com/splitting@1.0.6/dist/splitting.min.js'></script>
      <script src="./script.js"></script>
    
    </body>
    
    </html>

    CSS :

    This CSS sets up a full-screen dark UI using grid layout where each .planet section is positioned and styled with titles, images, and details; it uses custom variables for smooth animations and transitions like sliding text (.char) and fading content when a planet becomes active (data-active), while also styling small info blocks (tilt, gravity, hours) and an SVG-based navigation at the bottom that rotates based on the selected planet.

    @import url("https://fonts.googleapis.com/css?family=DM+Sans:400,700&display=swap");
    :root {
      --duration: .8s;
      --half-duraiton: calc( var(--duration) / 2 );
      --ease: cubic-bezier(.7, 0, .3, 1);
    }
    
    *, *:before, *:after {
      box-sizing: border-box;
      position: relative;
    }
    
    html, body {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
    }
    
    body {
      background: black;
      color: white;
      font-family: "DM Sans", sans-serif;
    }
    
    img {
      max-width: 100%;
    }
    
    #app {
      height: 100%;
      width: 100%;
      display: grid;
      grid-template-columns: 1;
      grid-template-rows: 1fr 1fr;
    }
    
    .planet {
      grid-column: 1;
      grid-row: 1/-1;
      overflow: hidden;
      height: 100%;
      width: 100%;
      display: grid;
      grid-template-columns: 10% 40% 40% 10%;
      grid-template-rows: 10% 1fr 1fr;
      grid-template-areas: "header header header header" "x title details y" "x planet photos photos";
    }
    .planet > .planet-title {
      display: block;
      grid-area: title;
    }
    .planet > .planet-figure {
      grid-column: 1/-1;
      grid-row: planet;
      padding: 0;
      margin: 0 auto;
      position: relative;
    }
    .planet > .planet-figure img {
      margin-bottom: -50%;
    }
    .planet > .planet-figure::after {
      content: "";
      position: fixed;
      bottom: 0%;
      top: 0%;
      width: 100%;
      left: 0;
      background: linear-gradient(to top, rgba(0, 0, 0, 0.7) 0%, transparent 30%);
      z-index: 2;
    }
    .planet > .planet-details {
      grid-area: details;
      display: flex;
      flex-direction: row;
      justify-content: space-between;
    }
    
    .detail {
      font-size: 5vmin;
      width: 3em;
      font-weight: 400;
      display: flex;
      margin-left: 0.4em;
      flex-shrink: 0;
      align-self: start;
    }
    .detail:after {
      content: attr(data-postfix);
    }
    .detail:before {
      display: block;
      position: absolute;
      top: 100%;
      margin-top: 1rem;
      font-size: 0.75rem;
      text-transform: uppercase;
      opacity: 0.6;
      letter-spacing: 1px;
    }
    .detail[data-detail=hours]:before {
      content: "Hours";
    }
    .detail[data-detail=gravity]:before {
      content: "gravity";
    }
    .detail[data-detail=tilt]:before {
      content: "tilt";
    }
    
    h1, h2 {
      margin: 0;
    }
    
    /* ---------------------------------- */
    .planet {
      visibility: hidden;
      transition: visibility 0.01s linear var(--duration);
      /* ---------------------------------- */
      /* ---------------------------------- */
      /* ---------------------------------- */
    }
    .planet[data-active] {
      visibility: visible;
      opacity: 1;
      transition-delay: 0s;
    }
    .planet .planet-title .word {
      overflow: hidden;
    }
    .planet .planet-title .char {
      transform: translateY(100%);
      transition: transform var(--duration) var(--ease);
      transition-delay: calc( var(--char-index) * .1s );
    }
    .planet[data-active] .planet-title .char {
      transform: translateY(0%);
      transition-delay: calc( (var(--duration)/2) + (var(--char-index) * .1s) );
    }
    .planet .planet-description {
      visibility: hidden;
      opacity: 0;
      transform: translateY(1em);
      transition: transform var(--duration) var(--ease), opacity var(--duration) linear, visibility 0.01s linear var(--duration);
    }
    .planet[data-active] .planet-description {
      opacity: 1;
      transform: translateY(0);
      visibility: visible;
      transition-delay: var(--duration), var(--duration), 0s;
    }
    .planet .planet-details {
      visibility: hidden;
    }
    .planet[data-active] .planet-details {
      opacity: 1;
      transform: translateY(0);
      visibility: visible;
      transition-delay: 0s;
    }
    .planet .planet-figure {
      opacity: 0;
      transition: opacity var(--duration) var(--ease);
    }
    .planet[data-active] .planet-figure {
      opacity: 1;
    }
    
    /* ---------------------------------- */
    #app {
      overflow: hidden;
    }
    
    .planet-nav {
      grid-column: 1;
      grid-row: 2;
      pointer-events: none;
      z-index: 10;
      display: flex;
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
    }
    .planet-nav svg {
      display: block;
      width: auto;
      height: auto;
      min-width: 100%;
      max-width: none;
      min-height: 100vh;
      margin-bottom: -50%;
    }
    @media (max-width: 600px) {
      .planet-nav svg {
        margin-bottom: -55%;
      }
    }
    .planet-nav tspan {
      cursor: pointer;
      fill: #FFF;
      pointer-events: auto;
      opacity: 0;
      transition: opacity var(--duration) linear;
    }
    .planet-nav tspan[x] {
      opacity: 0.6;
    }
    .planet-nav tspan:hover, .planet-nav tspan:focus {
      opacity: 1;
    }
    .planet-nav svg {
      transform-origin: center center;
      --length: 7;
      --range: 160deg;
      transform: rotate(calc( (var(--active,0) / var(--length)) * (-1 * var(--range)) + (var(--range) / 2) ));
      transition: transform var(--duration) var(--ease);
    }
    .planet-nav tspan {
      cursor: pointer;
    }

    JavaScript:

    The JS controls planet switching by storing all planets in an object, tracking the current one, and updating UI when a new planet is selected; it uses Splitting.js to animate text characters, custom animate() functions to smoothly change numbers (hours, tilt, gravity), and event listeners on SVG text (tspan) so clicking a planet name updates the active planet, rotates the nav, and animates values dynamically.

    console.clear();
    
    Splitting({ target: '.planet-title h1', by: 'chars' });
    
    const elApp = document.querySelector('#app');
    
    const elPlanets = Array.from(document.querySelectorAll('[data-planet]')).
      reduce((acc, el) => {
        const planet = el.dataset.planet;
    
        acc[planet] = el;
    
        return acc;
      }, {});
    
    const planetKeys = Object.keys(elPlanets);
    
    function getDetails(planet) {
      // tilt, gravity, hours
      const details = Array.from(elPlanets[planet].
        querySelectorAll(`[data-detail]`)).
        reduce((acc, el) => {
          acc[el.dataset.detail] = el.innerHTML.trim();
    
          return acc;
        }, { planet });
    
      return details;
    }
    
    // ...........
    
    let currentPlanetIndex = 0;
    let currentPlanet = getDetails('mercury');
    
    function selectPlanet(planet) {
      const prevPlanet = currentPlanet;
      const elActive = document.querySelector('[data-active]');
    
      delete elActive.dataset.active;
    
      const elPlanet = elPlanets[planet];
    
      elPlanet.dataset.active = true;
      currentPlanet = getDetails(elPlanet.dataset.planet);
    
      console.log(prevPlanet, currentPlanet);
    
      const elHoursDetail = elPlanet.querySelector('[data-detail="hours"]');
      animate.fromTo({
        from: +prevPlanet.hours,
        to: +currentPlanet.hours
      },
        value => {
          elHoursDetail.innerHTML = Math.round(value);
        });
    
      const elTiltDetail = elPlanet.querySelector('[data-detail="tilt"]');
      animate.fromTo({
        from: +prevPlanet.tilt,
        to: +currentPlanet.tilt
      },
        value => {
          elTiltDetail.innerHTML = value.toFixed(2);
        });
    
      const elGravityDetail = elPlanet.querySelector('[data-detail="gravity"]');
    
      animate.fromTo({
        from: +prevPlanet.gravity,
        to: +currentPlanet.gravity
      },
        value => {
          elGravityDetail.innerHTML = value.toFixed(1);
        });
    }
    
    function selectPlanetByIndex(i) {
      currentPlanetIndex = i;
      elApp.style.setProperty('--active', i);
      selectPlanet(planetKeys[i]);
    }
    
    // document.body.addEventListener('click', () => {
    //   currentPlanetIndex = (currentPlanetIndex + 1) % planetKeys.length;
    
    //   selectPlanet(planetKeys[currentPlanetIndex]);
    // });
    
    
    /* ---------------------------------- */
    
    function animate(duration, fn) {
      const start = performance.now();
      const ticks = Math.ceil(duration / 16.666667);
      let progress = 0; // between 0 and 1, +/-
    
      function tick(now) {
        if (progress >= 1) {
          fn(1);
          return;
        }
    
        const elapsed = now - start;
        progress = elapsed / duration;
    
        // callback
        fn(progress); // number between 0 and 1
    
        requestAnimationFrame(tick); // every 16.6666667 ms
      }
    
      tick(start);
    }
    
    function easing(progress) {
      return (1 - Math.cos(progress * Math.PI)) / 2;
    }
    
    const animationDefaults = {
      duration: 1000,
      easing
    };
    
    
    animate.fromTo = ({
      from,
      to,
      easing,
      duration },
      fn) => {
      easing = easing || animationDefaults.easing;
      duration = duration || animationDefaults.duration;
    
      const delta = +to - +from;
    
      return animate(duration, progress => fn(from + easing(progress) * delta));
    };
    
    
    /* ---------------------------------- */
    
    const svgNS = 'http://www.w3.org/2000/svg';
    const elSvgNav = document.querySelector('.planet-nav svg');
    
    const elTspans = [...document.querySelectorAll('tspan')];;
    const length = elTspans.length - 1;
    
    elSvgNav.style.setProperty('--length', length);
    
    // Getting the length for distributing the text along the path
    const elNavPath = document.querySelector('#navPath');
    const elLastTspan = elTspans[length];
    const navPathLength = elNavPath.getTotalLength() - elLastTspan.getComputedTextLength();
    
    elTspans.forEach((tspan, i) => {
      let percent = i / length;
    
      tspan.setAttribute('x', percent * navPathLength);
      tspan.setAttributeNS(svgNS, 'x', percent * navPathLength);
    
      tspan.addEventListener('click', e => {
        e.preventDefault();
        selectPlanetByIndex(i);
      });
    
    });

    In conclusion, this Solar System Planet Picker Animation helps you understand how to combine HTML, CSS, and JavaScript to create a highly interactive and visually engaging UI. You learn how to structure dynamic content, use animations and transitions for smooth user experience, and control everything with JavaScript logic like state management and event handling 🚀

    If your project has problems, don’t worry. Just click to download the source code and face your coding challenges with excitement. Have fun coding!

    Animation magic magic navigation menu menu naviagtion Web Design
    Share. Copy Link Twitter Facebook LinkedIn Email WhatsApp
    Previous ArticleHow to make Glowing Tab Navigation using HTML CSS & JavaScript
    Coding Stella
    • Website

    Related Posts

    JavaScript

    How to make Glowing Tab Navigation using HTML CSS & JavaScript

    9 April 2026
    JavaScript

    How to create Nike Shoes Animation using HTML CSS and JS

    8 April 2026
    JavaScript

    How to create Creepy Eye Button using HTML CSS and JS

    3 April 2026
    Add A Comment
    Leave A Reply Cancel Reply

    Trending Post

    Master Frontend in 100 Days Ebook

    2 March 202432K Views

    How to make Modern Login Form using HTML & CSS | Glassmorphism

    11 January 202431K Views

    How to make I love you Animation in HTML CSS & JavaScript

    14 February 202424K Views

    How to make Valentine’s Day Card using HTML & CSS

    13 February 202415K Views
    Follow Us
    • Instagram
    • Facebook
    • YouTube
    • Twitter
    ads
    Featured Post

    How to create Animated Credit Card using HTML CSS and JS

    9 August 2025

    How to create Spider Clock Animation using HTML CSS and JS

    26 October 2025

    How to make Animated Search Bar Input using HTML and CSS

    5 November 2025

    How to create Heart Animation using HTML CSS and JS

    11 July 2025
    Latest Post

    How to make Solar System Planet Picker Animation using HTML CSS & JavaScript

    10 April 2026

    How to make Glowing Tab Navigation using HTML CSS & JavaScript

    9 April 2026

    How to create Nike Shoes Animation using HTML CSS and JS

    8 April 2026

    How to Make Animated Login Form in HTML and CSS

    4 April 2026
    Facebook X (Twitter) Instagram YouTube
    • About Us
    • Privacy Policy
    • Return and Refund Policy
    • Terms and Conditions
    • Contact Us
    • Buy me a coffee
    © 2026 Coding Stella. Made with 💙 by @coding.stella

    Type above and press Enter to search. Press Esc to cancel.

    Ad Blocker Enabled!
    Ad Blocker Enabled!
    Looks like you're using an ad blocker. We rely on advertising to help fund our site.
    Okay! I understood