<fieldset class="ui-wheel-of-fortune" style="--_items: 1;">
  <ul data-itemCount="1">
    <li>$1000</li>
  </ul>
  <button type="button">SPIN</button>
</fieldset>

<fieldset class="ui-wheel-of-fortune" style="--_items: 2;">
  <ul data-itemCount="2">
    <li>$1000</li>
    <li>$2000</li>
  </ul>
  <button type="button">SPIN</button>
</fieldset>

<fieldset class="ui-wheel-of-fortune" style="--_items: 3;">
  <ul data-itemCount="3">
    <li>$1000</li>
    <li>$2000</li>
    <li>$3000</li>
  </ul>
  <button type="button">SPIN</button>
</fieldset>

<fieldset class="ui-wheel-of-fortune" style="--_items: 12;">
  <ul data-itemCount="12">
    <li>$1000</li>
    <li>$2000</li>
    <li>$3000</li>
    <li>$4000</li>
    <li>$5000</li>
    <li>$6000</li>
    <li>$7000</li>
    <li>$8000</li>
    <li>$9000</li>
    <li>$10000</li>
    <li>$11000</li>
    <li>$12000</li>
  </ul>
  <button type="button">SPIN</button>
</fieldset>
:where(.ui-wheel-of-fortune) {
  all: unset;
  margin-top: 30px;
  aspect-ratio: 1 / 1;
  container-type: inline-size;
  direction: ltr;
  display: grid;
  position: relative;
  width: 100%;
  &::after {
    aspect-ratio: 1/cos(30deg);
    background-color: crimson;
    clip-path: polygon(50% 100%,100% 0,0 0);
    content: "";
    height: 4cqi;
    position: absolute;
    place-self: start center;
    scale: 1.4;
  }

  & > * { position: absolute; }

  button {
    aspect-ratio: 1 / 1;
    background: hsla(0, 0%, 100%, .8);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    font-size: 5cqi;
    place-self: center;
    width: 20cqi;
  }

  ul {
    all: unset;
    clip-path: inset(0 0 0 0 round 50%);
    display: grid;
    inset: 0;
    place-content: center start;

    li {
      align-content: center;
      aspect-ratio: 1 / calc(2 * tan(180deg / var(--_items)));
      background: hsl(calc(360deg / var(--_items) * calc(var(--_idx))), 100%, 75%);
      clip-path: polygon(0% 0%, 100% 50%, 0% 100%);
      display: grid;
      font-size: 5cqi;
      grid-area: 1 / -1;
      padding-left: 1ch;
      rotate: calc(360deg / var(--_items) * calc(var(--_idx) - 1));
      transform-origin: center right;
      user-select: none;
      width: 50cqi;

      &:nth-of-type(1) { --_idx: 1; }
      &:nth-of-type(2) { --_idx: 2; }
      &:nth-of-type(3) { --_idx: 3; }
      &:nth-of-type(4) { --_idx: 4; }
      &:nth-of-type(5) { --_idx: 5; }
      &:nth-of-type(6) { --_idx: 6; }
      &:nth-of-type(7) { --_idx: 7; }
      &:nth-of-type(8) { --_idx: 8; }
      &:nth-of-type(9) { --_idx: 9; }
      &:nth-of-type(10) { --_idx: 10; }
      &:nth-of-type(11) { --_idx: 11; }
      &:nth-of-type(12) { --_idx: 12; }
    }
          &[data-itemCount='1'] {
        li {
          aspect-ratio: 1/1;
          display: block;
          rotate: 0;
          clip-path: none;
          width: 100cqi;
        }
      }
      &[data-itemCount='2'] {
        li {
          height: 100cqi;
          clip-path: none;
        }
      }
      &[data-itemCount='3'] {
        li {
          aspect-ratio: 1 / 2;
          clip-path: polygon(-35% -100%, 100% 50%, 0% 145%);
        }
      }

  }
}

/* for demo */
* { box-sizing: border-box; }
body {
  font-family: system-ui, sans-serif;
  padding: 5cqi;
}
/*
JavaScript only required for spin interaction, not for rendering the component.
*/
function getResultsAtTop(spinnerElement) {
  if (!spinnerElement) return null;
  
  const rect = spinnerElement.getBoundingClientRect();
  const centerX = rect.left + rect.width / 2;
  const topY = rect.top + (.05 * rect.height); // the arrow is 4%, so we use 5%
  const element = document.elementFromPoint(centerX, topY);
  if (element?.parentElement?.parentElement !== spinnerElement) return null;
  return element?.textContent?.trim() || null;
}

function wheelOfFortune(node) {
  if (!node) return;

  const spin = node.querySelector('button');
  const wheel = node.querySelector('ul');
  let animation;
  let previousEndDegree = 0;

  spin.addEventListener('click', () => {
    if (animation) {
      animation.cancel(); // Reset the animation if it already exists
    }

    const randomAdditionalDegrees = Math.random() * 360 + 1800;
    const newEndDegree = previousEndDegree + randomAdditionalDegrees;

    animation = wheel.animate([
      { transform: `rotate(${previousEndDegree}deg)` },
      { transform: `rotate(${newEndDegree}deg)` }
    ], {
      duration: 4000,
      direction: 'normal',
      easing: 'cubic-bezier(0.440, -0.205, 0.000, 1.130)',
      fill: 'forwards',
      iterations: 1
    });

    previousEndDegree = newEndDegree;
    animation.onfinish = () => {
      const currentValue = getResultsAtTop(node);
      spin.textContent = currentValue;
    };
  });
}

// Usage
document.querySelectorAll('.ui-wheel-of-fortune').forEach(el => wheelOfFortune(el))
// wheelOfFortune('.ui-wheel-of-fortune');

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.