Skip to content

Gallery / interactive / Fluid star rating

Fluid star rating

Five-star rating with fluid fill and pop, radio-powered, zero JS

interactive advanced interactiveratingstarsradioform
Live preview

Techniques: radio-group · row-reverse · sibling-combinator · :checked · @keyframes

Customizeupdates preview, code & clipboard
#EFBB33
36px
0.5s
Code snippets/interactive/rating-stars-fluid.html
<!--
  ============================================================
  SVGarden — https://www.svgarden.dev
  Author : Simon-Pierre Boucher
  Contact: contact@spboucher.ai
  File   : snippets/interactive/rating-stars-fluid.html
  Desc   : Five-star rating with fluid fill and pop, radio-powered, zero JS
  ============================================================
-->
<fieldset class="sg-rating-stars-fluid" style="--sg-color:#EFBB33; --sg-size:36px; --sg-duration:0.5s;">
  <legend class="sg-rating-stars-fluid-sr">Rate this from one to five stars</legend>
  <input class="sg-rating-stars-fluid-in" type="radio" name="sg-rating-stars-fluid" id="sg-rating-stars-fluid-5" value="5" />
  <label class="sg-rating-stars-fluid-star" for="sg-rating-stars-fluid-5" aria-label="5 stars">
    <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <circle class="sg-rating-stars-fluid-pop" cx="12" cy="12" r="10" />
      <polygon points="12,2.5 14.9,9 22,9.7 16.7,14.5 18.2,21.5 12,17.8 5.8,21.5 7.3,14.5 2,9.7 9.1,9" />
    </svg>
  </label>
  <input class="sg-rating-stars-fluid-in" type="radio" name="sg-rating-stars-fluid" id="sg-rating-stars-fluid-4" value="4" />
  <label class="sg-rating-stars-fluid-star" for="sg-rating-stars-fluid-4" aria-label="4 stars">
    <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <circle class="sg-rating-stars-fluid-pop" cx="12" cy="12" r="10" />
      <polygon points="12,2.5 14.9,9 22,9.7 16.7,14.5 18.2,21.5 12,17.8 5.8,21.5 7.3,14.5 2,9.7 9.1,9" />
    </svg>
  </label>
  <input class="sg-rating-stars-fluid-in" type="radio" name="sg-rating-stars-fluid" id="sg-rating-stars-fluid-3" value="3" />
  <label class="sg-rating-stars-fluid-star" for="sg-rating-stars-fluid-3" aria-label="3 stars">
    <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <circle class="sg-rating-stars-fluid-pop" cx="12" cy="12" r="10" />
      <polygon points="12,2.5 14.9,9 22,9.7 16.7,14.5 18.2,21.5 12,17.8 5.8,21.5 7.3,14.5 2,9.7 9.1,9" />
    </svg>
  </label>
  <input class="sg-rating-stars-fluid-in" type="radio" name="sg-rating-stars-fluid" id="sg-rating-stars-fluid-2" value="2" />
  <label class="sg-rating-stars-fluid-star" for="sg-rating-stars-fluid-2" aria-label="2 stars">
    <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <circle class="sg-rating-stars-fluid-pop" cx="12" cy="12" r="10" />
      <polygon points="12,2.5 14.9,9 22,9.7 16.7,14.5 18.2,21.5 12,17.8 5.8,21.5 7.3,14.5 2,9.7 9.1,9" />
    </svg>
  </label>
  <input class="sg-rating-stars-fluid-in" type="radio" name="sg-rating-stars-fluid" id="sg-rating-stars-fluid-1" value="1" />
  <label class="sg-rating-stars-fluid-star" for="sg-rating-stars-fluid-1" aria-label="1 star">
    <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <circle class="sg-rating-stars-fluid-pop" cx="12" cy="12" r="10" />
      <polygon points="12,2.5 14.9,9 22,9.7 16.7,14.5 18.2,21.5 12,17.8 5.8,21.5 7.3,14.5 2,9.7 9.1,9" />
    </svg>
  </label>
</fieldset>
<style>
  .sg-rating-stars-fluid {
    display: flex;
    flex-direction: row-reverse;
    justify-content: center;
    gap: 0.3rem;
    border: 0;
    margin: 0;
    padding: 0;
  }
  .sg-rating-stars-fluid-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .sg-rating-stars-fluid-in {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
  }
  .sg-rating-stars-fluid-star {
    width: var(--sg-size);
    cursor: pointer;
  }
  .sg-rating-stars-fluid-star svg {
    display: block;
    width: 100%;
    overflow: visible;
  }
  .sg-rating-stars-fluid-star polygon {
    fill: transparent;
    stroke: rgba(128, 128, 128, 0.55);
    stroke-width: 1.4;
    stroke-linejoin: round;
    transform-box: fill-box;
    transform-origin: center;
    transition: fill 0.15s ease, stroke 0.15s ease;
  }
  .sg-rating-stars-fluid-star:hover polygon,
  .sg-rating-stars-fluid-star:hover ~ .sg-rating-stars-fluid-star polygon,
  .sg-rating-stars-fluid-in:checked + .sg-rating-stars-fluid-star polygon,
  .sg-rating-stars-fluid-in:checked ~ .sg-rating-stars-fluid-star polygon {
    fill: var(--sg-color);
    stroke: var(--sg-color);
  }
  .sg-rating-stars-fluid-in:checked + .sg-rating-stars-fluid-star polygon {
    animation: sg-rating-stars-fluid-spring var(--sg-duration) cubic-bezier(0.3, 1.8, 0.5, 1);
  }
  .sg-rating-stars-fluid-pop {
    fill: none;
    stroke: var(--sg-color);
    stroke-width: 1.2;
    stroke-dasharray: 1.5 5;
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
  }
  .sg-rating-stars-fluid-in:checked + .sg-rating-stars-fluid-star .sg-rating-stars-fluid-pop {
    animation: sg-rating-stars-fluid-burst var(--sg-duration) ease-out;
  }
  .sg-rating-stars-fluid-in:focus-visible + .sg-rating-stars-fluid-star {
    outline: 2px solid var(--sg-color);
    outline-offset: 2px;
    border-radius: 6px;
  }
  @keyframes sg-rating-stars-fluid-spring {
    0%   { transform: scale(0.6); }
    100% { transform: scale(1); }
  }
  @keyframes sg-rating-stars-fluid-burst {
    0%   { opacity: 0.9; transform: scale(0.5); }
    100% { opacity: 0; transform: scale(1.5); }
  }
</style>

More interactive