npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@mertercelik/react-prize-wheel

v1.0.2

Published

A customizable and animated prize wheel component for React

Readme

React Prize Wheel

A highly customizable, animated prize wheel component for React applications with TypeScript support.

Demo

Live Demo

Installation

npm install @mertercelik/react-prize-wheel
yarn add @mertercelik/react-prize-wheel
pnpm add @mertercelik/react-prize-wheel

Quick Start

import { useRef } from 'react';
import { PrizeWheel } from '@mertercelik/react-prize-wheel';
import type { Sector, PrizeWheelRef } from '@mertercelik/react-prize-wheel';
import '@mertercelik/react-prize-wheel/style.css';

function App() {
  const wheelRef = useRef<PrizeWheelRef>(null);

  const sectors: Sector[] = [
    { id: 1, label: 'Prize 1', probability: 10 },
    { id: 2, label: 'Prize 2', probability: 20 },
    { id: 3, label: 'Prize 3', probability: 15 },
    { id: 4, label: 'Prize 4', probability: 5 },
  ];

  const handleSpinEnd = (sector: Sector) => {
    console.log('Winner:', sector.label);
  };

  return (
    <div>
      <PrizeWheel
        ref={wheelRef}
        sectors={sectors}
        onSpinEnd={handleSpinEnd}
      />
      <button onClick={() => wheelRef.current?.spin()}>
        Spin the Wheel
      </button>
    </div>
  );
}

API Reference

PrizeWheel Component

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | sectors | Sector[] | required | Array of prize sectors | | onSpinStart | () => void | undefined | Callback fired when spin starts | | onSpinEnd | (sector: Sector) => void | undefined | Callback fired when spin ends with winning sector | | duration | number | 4 | Spin duration in seconds | | minSpins | number | 5 | Minimum number of full rotations | | maxSpins | number | 8 | Maximum number of full rotations |

Customization Props

Colors

| Prop | Type | Default | Description | |------|------|---------|-------------| | frameColor | string | '#ddd' | Outer frame color | | middleColor | string | '#ddd' | Center circle color | | middleDotColor | string | '#bbb' | Center dot color | | winIndicatorColor | string | '#ddd' | Win indicator arrow color | | winIndicatorDotColor | string | '#bbb' | Win indicator dot color | | sticksColor | string | '#ddd' | Divider sticks color | | wheelColors | [string, string] | ['#1592e8', '#14c187'] | Alternating sector colors | | borderColor | string | '#ddd' | Sector border color | | textColor | string | '#fff' | Sector text color |

Styling

| Prop | Type | Default | Description | |------|------|---------|-------------| | borderWidth | number | 2 | Sector border width in pixels | | textFontSize | number | 18 | Sector text font size in pixels |

Shadows

| Prop | Type | Default | Description | |------|------|---------|-------------| | wheelShadowColor | string | '#000' | Wheel shadow color | | wheelShadowOpacity | number | 0.15 | Wheel shadow opacity (0-1) | | middleShadowColor | string | '#000' | Middle circle shadow color | | middleShadowOpacity | number | 0.2 | Middle circle shadow opacity (0-1) | | indicatorShadowColor | string | '#000' | Indicator shadow color | | indicatorShadowOpacity | number | 0.22 | Indicator shadow opacity (0-1) |

Sector Interface

interface Sector {
  id: number | string;
  label: string;
  text?: string;
  probability?: number;
}

| Property | Type | Required | Description | |----------|------|----------|-------------| | id | number \| string | Yes | Unique identifier for the sector | | label | string | Yes | Label returned in callbacks | | text | string | No | Text displayed on the sector (defaults to label) | | probability | number | No | Relative probability weight (default: 10) |

Ref API

The component exposes a ref with the following methods and properties:

interface PrizeWheelRef {
  spin: () => void;
  isSpinning: boolean;
}

| Member | Type | Description | |--------|------|-------------| | spin | () => void | Programmatically trigger a spin | | isSpinning | boolean | Current spinning state |

Advanced Usage

Custom Button with State

import { useRef, useState } from 'react';
import { PrizeWheel } from '@mertercelik/react-prize-wheel';
import type { Sector, PrizeWheelRef } from '@mertercelik/react-prize-wheel';
import '@mertercelik/react-prize-wheel/style.css';

function App() {
  const wheelRef = useRef<PrizeWheelRef>(null);
  const [isSpinning, setIsSpinning] = useState(false);
  const [winner, setWinner] = useState<Sector | null>(null);

  const handleSpinStart = () => {
    setIsSpinning(true);
    setWinner(null);
  };

  const handleSpinEnd = (sector: Sector) => {
    setIsSpinning(false);
    setWinner(sector);
  };

  return (
    <div>
      <PrizeWheel
        ref={wheelRef}
        sectors={sectors}
        onSpinStart={handleSpinStart}
        onSpinEnd={handleSpinEnd}
      />
      <button 
        onClick={() => wheelRef.current?.spin()}
        disabled={isSpinning}
      >
        {isSpinning ? 'Spinning...' : 'Spin the Wheel'}
      </button>
      {winner && <p>Winner: {winner.label}</p>}
    </div>
  );
}

Probability System

The probability system uses relative weights. Higher values increase the chance of winning.

const sectors = [
  { id: 1, label: 'Common', probability: 50 },   // 50% chance
  { id: 2, label: 'Uncommon', probability: 30 }, // 30% chance
  { id: 3, label: 'Rare', probability: 15 },     // 15% chance
  { id: 4, label: 'Legendary', probability: 5 }, // 5% chance
];

Full Customization

<PrizeWheel
  ref={wheelRef}
  sectors={sectors}
  onSpinStart={handleSpinStart}
  onSpinEnd={handleSpinEnd}
  duration={6}
  minSpins={4}
  maxSpins={4}
  frameColor="#ffd700"
  middleColor="#ffd700"
  middleDotColor="#8b7500"
  winIndicatorColor="#ffd700"
  winIndicatorDotColor="#8b7500"
  sticksColor="#ffd700"
  wheelColors={['#0a1d3f', '#0a2249']}
  borderColor="#ffd700"
  borderWidth={3}
  textColor="#ffffff"
  textFontSize={20}
  wheelShadowColor="#000"
  wheelShadowOpacity={0.2}
  middleShadowColor="#000"
  middleShadowOpacity={0.25}
  indicatorShadowColor="#000"
  indicatorShadowOpacity={0.3}
/>

TypeScript

The package includes full TypeScript definitions. Import types as needed:

import type { 
  Sector, 
  PrizeWheelProps, 
  PrizeWheelRef 
} from '@mertercelik/react-prize-wheel';

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Dependencies

  • React 18+
  • GSAP 3+

Credits

The wheel SVG design is based on the work by Soma Szoboszlai.

License

MIT

Acknowledgments

  • Wheel design inspiration: Soma Szoboszlai
  • Animation library: GSAP

Contributing

Contributions are welcome. Please open an issue or submit a pull request.

Support

For issues and feature requests, please use the GitHub issue tracker.