vue-wheel-spinner

A Vue.js component that provides wheel spinner
3,988 14
Install
npm install vue-wheel-spinner
Latest Version:0.2.8
Vue:3
License:MIT
Last Updated:Apr 4, 2026
Links: GitHub  ·  npm
Maintainer: ozkurtilyas

Wheel Spinner Component

A customizable wheel spinner component built with Vue.js.

image

Table of Contents

Installation

To use this component, you need to have a Vue.js project set up. If you don't have one, you can create a new Vue.js project using Vue CLI:

npm install -g @vue/cli
vue create my-project
cd my-project

Install the component

npm install vue-wheel-spinner

Usage

Import and register the component in your Vue component:


<template>

  <VueWheelSpinner
      ref="spinner"
      :slices="slices"
      :slice-font-style="sliceFontStyle"
      :slice-text-position="sliceTextPosition"
      :winner-index="defaultWinner"
      :sounds="sounds"
      :cursor-angle="cursorAngle"
      :cursor-position="cursorPosition"
      :cursor-distance="cursorDistance"
      @spin-start="onSpinStart"
      @spin-end="onSpinEnd">

    <template #cursor>
      <img class="cursor-img" :src="https://raw.githubusercontent.com/ilyasozkurt/vue-wheel-spinner/HEAD/cursorImage" alt="Cursor">
    </template>

    <template #default>
      <button
          class="spin-button"
          :disabled="isSpinning"
          @click="handleSpinButtonClick"
          @mouseover="handleSpinButtonHover"
          @mouseleave="handleSpinButtonLeave">
        Spin
      </button>
    </template>

  </VueWheelSpinner>

</template>

<script>
  import VueWheelSpinner from 'vue-wheel-spinner';

  import cursorImage from './assets/cursor.svg';
  import wonSound from './sounds/won.mp3';
  import clickSound from './sounds/click.mp3';
  import hoverSound from './sounds/hover.mp3';
  import leaveSound from './sounds/leave.mp3';
  import spinningSound from './sounds/spinning.mp3';

  export default {
    components: {
      VueWheelSpinner
    },
    data() {
      return {
        winnerResult: null,
        slices: [
          {color: '#eb4d4b', text: 'Slice 1', textColor: '#000000'},
          {color: '#f0932b', text: 'Slice 2', textColor: '#ffffff'},
          {color: '#f9ca24', text: 'Slice 3', textColor: '#000000'},
          {color: '#badc58', text: 'Slice 4', textColor: '#ffffff'},
          {color: '#7ed6df', text: 'Slice 5', textColor: '#000000'},
          {color: '#e056fd', text: 'Slice 6', textColor: '#ffffff'},
        ],
        sliceFontStyle: 'bold 16px Arial',
        sliceTextPosition: 'edge',
        isSpinning: false,
        defaultWinner: 0,
        sounds: {
          won: wonSound,
          spinButtonClick: clickSound,
          spinButtonHover: hoverSound,
          spinButtonLeave: leaveSound,
          spinning: spinningSound
        },
        cursorImage,
        cursorAngle: 0,
        cursorPosition: 'edge',
        cursorDistance: 0
      };
    },
    methods: {
      playAudio(audio) {
        if (audio) {
          audio.volume = 0.5
          audio.play();
        }
      },
      handleSpinButtonClick() {
        if (this.buttonClickAudio) {
          this.playAudio(this.buttonClickAudio)
        }
        this.$refs.spinner.spinWheel(this.defaultWinner);
      },
      handleSpinButtonHover() {
        if (this.buttonHoverAudio) {
          this.playAudio(this.buttonHoverAudio)
        }
      },
      handleSpinButtonLeave() {
        if (this.buttonLeaveAudio) {
          this.playAudio(this.buttonLeaveAudio)
        }
      },
      spinFor(index) {
        this.defaultWinner = index;
        this.$refs.spinner.spinWheel(index);
      },
      onSpinStart() {
        this.winnerResult = null;
        this.isSpinning = true;
      },
      onSpinEnd(winnerIndex) {
        this.isSpinning = false;
        this.winnerResult = this.slices[winnerIndex];
      }
    },
    mounted() {
      this.buttonHoverAudio = new Audio(hoverSound);
      this.buttonLeaveAudio = new Audio(leaveSound);
      this.buttonClickAudio = new Audio(clickSound);
    }
  };
</script>

<style>

  .cursor-img {
    width: 50px;
    aspect-ratio: 1 / 1;
    filter: drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.19));
  }

  .spin-button {
    width: 100px;
    height: 100px;
    margin: 0 auto;
    aspect-ratio: 1 / 1;
    font-size: 20px;
    cursor: pointer;
    background: #eb4d4b;
    border-radius: 50%;
    transition: all 150ms;
    border: 10px solid white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    color: white !important;
    box-shadow: inset -3px -3px 2px 2px rgba(0, 0, 0, 0.19), 3px 3px 2px 2px rgba(0, 0, 0, 0.19);
    z-index: 11;
    position: relative;
    user-select: none;

    &:hover {
      box-shadow: inset -5px -5px 2px 2px rgba(0, 0, 0, 0.19), 3px 3px 2px 2px rgba(0, 0, 0, 0.19);
    }

    &:active {
      box-shadow: inset 3px 3px 2px 2px rgba(0, 0, 0, 0.19), 3px 3px 2px 2px rgba(0, 0, 0, 0.19);
    }

    &:disabled {
      background: #ccc;
      cursor: not-allowed;
      pointer-events: none;
    }

  }

</style>

Props

Prop Type Default Description
slices Array required Array of slice objects. Each slice object should have color and text properties.
sliceFontStyle String 'bold 16px Arial' Font style for the slice text.
sliceTextPosition String 'edge' Position of the slice text. Can be 'edge', 'center' or 'middle'.
winnerIndex Number 0 Index of the slice that will be the winner.
spinDuration Number 4000 Duration of the spin animation in milliseconds.
cursorAngle Number 0 Angle of the cursor.
cursorPosition String 'edge' Position of the cursor. Can be 'edge' or 'center'.
cursorDistance Number 0 Distance of the cursor from the center or edge. It's depending to cursorPosition
sounds Object {} Object of sound files.
sounds.won String null Sound file for the winning event.
sounds.spinning String null Sound file for the spinning event.

Slots

Slot Description
cursor Slot for the cursor element. Mostly an image like a cursor
default Slot for centered content. Mostly a circle spin button

Events

Event Description
spin-start Emitted when the spin starts.
spin-end Emitted when the spin ends. Passes the winnerIndex as a parameter.

License

This project is licensed under the MIT License.

Related Packages

spin-wheel

An easy to use, themeable component for randomising choices and prizes.

150,859 346
vue3-spinner

Spinners for Vue 3

43,594 11
vuejs-tree

A highly customizable vuejs tree

35,221 331
himmas-vue-calendar

A calendar component for Vue.js

5,301 45
vue-spinner

Spinners of Vue Components

1,461,459 1,807

Version History

Version Released Vue License
0.2.8 ^3.4.21 MIT
0.2.7 ^3.4.21 MIT
0.2.6 ^3.4.21 MIT
0.2.5 ^3.4.21 MIT
0.2.4 ^3.4.21 MIT