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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@crocogiciel/react-web-radial-menu

v1.0.6

Published

A beautiful and customizable radial menu component for React with multi-level navigation support

Downloads

57

Readme

React Radial Menu

A beautiful and customizable radial (circular) menu component for React with multi-level navigation support.

Features

  • Beautiful radial menu design with smooth animations
  • Multi-level navigation support (nested submenus)
  • Multiple selection with visual feedback
  • Customizable badge counters for parent items with children
  • Per-item color customization (background, hover, selected, badges)
  • Color inheritance from parent to children
  • Automatic gradient generation for submenus with customizable ranges
  • Fully customizable colors and sizes
  • TypeScript support with full type definitions
  • Configurable animation presets (fast, smooth, elastic, slow, none)
  • Text wrapping for long labels
  • Hover and selection states
  • Validation and cancel callbacks
  • Click outside to validate selection

Installation

From npm

npm install @crocogiciel/react-web-radial-menu

From GitHub

npm install crocogiciel/react-web-radial-menu

Peer Dependencies

This package requires the following peer dependencies:

{
  "react": "^18.3.1",
  "react-dom": "^18.3.1",
  "lucide-react": "^0.344.0"
}

Make sure these are installed in your project:

npm install react react-dom lucide-react

Basic Usage

import { RadialMenu } from '@crocogiciel/react-web-radial-menu';
import '@crocogiciel/react-web-radial-menu/styles.css';

function App() {
  const [showMenu, setShowMenu] = useState(false);

  const menuItems = [
    { id: '1', label: 'Home' },
    { id: '2', label: 'Settings' },
    { id: '3', label: 'Profile' },
    { id: '4', label: 'Help' },
  ];

  const handleValidate = (selectedIds: string[]) => {
    console.log('Selected:', selectedIds);
    setShowMenu(false);
  };

  const handleCancel = () => {
    console.log('Cancelled');
    setShowMenu(false);
  };

  return (
    <>
      <button onClick={() => setShowMenu(true)}>Open Menu</button>
      {showMenu && (
        <RadialMenu
          items={menuItems}
          position={{ x: 400, y: 400 }}
          centerText="Menu"
          onValidate={handleValidate}
          onCancel={handleCancel}
        />
      )}
    </>
  );
}

Advanced Usage with Submenus

import { RadialMenu, RadialMenuItem } from '@crocogiciel/react-web-radial-menu';

function App() {
  const [showMenu, setShowMenu] = useState(false);

  const menuItems: RadialMenuItem[] = [
    {
      id: '1',
      label: 'File',
      children: [
        { id: '1-1', label: 'New' },
        { id: '1-2', label: 'Open' },
        { id: '1-3', label: 'Save' },
      ],
    },
    {
      id: '2',
      label: 'Edit',
      children: [
        { id: '2-1', label: 'Cut' },
        { id: '2-2', label: 'Copy' },
        { id: '2-3', label: 'Paste' },
      ],
    },
    { id: '3', label: 'View' },
    { id: '4', label: 'Help' },
  ];

  const handleValidate = (selectedIds: string[]) => {
    console.log('Selected items:', selectedIds);
    setShowMenu(false);
  };

  const handleCancel = () => {
    console.log('Menu cancelled');
    setShowMenu(false);
  };

  return (
    <>
      <button onClick={() => setShowMenu(true)}>Open Menu</button>
      {showMenu && (
        <RadialMenu
          items={menuItems}
          position={{ x: 400, y: 400 }}
          centerText="Commands"
          radius={160}
          innerRadius={70}
          itemHeight={50}
          colors={{
            selected: '#10b981',
            unselected: '#374151',
            hover: '#4b5563',
            background: 'rgba(17, 24, 39, 0.95)',
            text: '#ffffff',
          }}
          badgeConfig={{
            backgroundColor: '#ef4444',
            textColor: '#ffffff',
            size: 20,
            fontSize: 12,
            show: true,
          }}
          animationPreset="smooth"
          animationDuration={300}
          onValidate={handleValidate}
          onCancel={handleCancel}
        />
      )}
    </>
  );
}

API Reference

RadialMenu Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | items | RadialMenuItem[] | required | Array of menu items | | position | { x: number, y: number } | { x: 400, y: 400 } | Position of the menu center | | colors | Partial<RadialMenuColors> | Default colors | Custom color scheme | | centerText | string | '' | Text displayed in the center | | onValidate | (selectedIds: string[]) => void | - | Callback when validation is triggered (includes clicking outside) | | onCancel | () => void | - | Callback when cancel button is clicked | | radius | number | 160 | Outer radius of the menu | | innerRadius | number | 70 | Inner radius of the menu | | itemHeight | number | 50 | Height of each menu item | | badgeConfig | BadgeConfig | {} | Configuration for selection count badges | | animationPreset | AnimationPreset | 'none' | Animation style: 'fast', 'smooth', 'elastic', 'slow', or 'none' | | animationDuration | number | 300 | Duration of animations in milliseconds | | autoGradient | boolean | false | Enable automatic gradient colors for submenus | | gradientLightnessRange | number | 20 | Lightness variation range for gradient (0-50%) | | gradientSaturationRange | number | 10 | Saturation variation range for gradient (0-30%) |

RadialMenuItem

interface RadialMenuItem {
  id: string;
  label: string;
  icon?: string;
  children?: RadialMenuItem[];
  category?: string;
  backgroundColor?: string;
  selectedColor?: string;
  hoverColor?: string;
  badgeConfig?: BadgeConfig;
}

RadialMenuColors

interface RadialMenuColors {
  selected: string;      // Color for selected items
  unselected: string;    // Color for unselected items
  hover: string;         // Color on hover
  background: string;    // Background color
  text: string;          // Text color
}

BadgeConfig

interface BadgeConfig {
  backgroundColor?: string;  // Badge background color
  textColor?: string;        // Badge text color
  size?: number;             // Badge diameter in pixels
  fontSize?: number;         // Badge font size in pixels
  show?: boolean;            // Whether to show badges
}

AnimationPreset

type AnimationPreset = 'fast' | 'smooth' | 'elastic' | 'slow' | 'none';

SelectedItems

interface SelectedItems {
  [key: string]: boolean;
}

An object mapping item IDs to their selection state.

Customization

Custom Colors

<RadialMenu
  items={items}
  colors={{
    selected: '#3b82f6',
    unselected: '#1e293b',
    hover: '#334155',
    background: 'rgba(0, 0, 0, 0.9)',
    text: '#f1f5f9',
  }}
/>

Custom Size

<RadialMenu
  items={items}
  radius={200}
  innerRadius={80}
  itemHeight={60}
/>

Badge Configuration

<RadialMenu
  items={items}
  badgeConfig={{
    backgroundColor: '#ef4444',
    textColor: '#ffffff',
    size: 24,
    fontSize: 14,
    show: true,
  }}
/>

Badges show the count of selected children for parent items with submenus.

Badge Positioning: Badges are automatically positioned at the first third (33%) of each arc segment, rather than at the center. This optimized placement provides better visual balance, improves readability, and prevents potential overlapping when multiple items with badges are present. The positioning is calculated dynamically based on the menu's radius and the configured badge size.

Custom Item Colors

You can specify custom colors for each menu item, including background, hover, selection, and badge colors. By default, submenus inherit their parent's colors.

const menuItems: RadialMenuItem[] = [
  {
    id: '1',
    label: 'File',
    backgroundColor: '#3b82f6',
    selectedColor: '#60a5fa',
    hoverColor: '#2563eb',
    badgeConfig: {
      backgroundColor: '#ef4444',
      textColor: '#ffffff',
      size: 20,
      fontSize: 12,
      show: true,
    },
    children: [
      { id: '1-1', label: 'New' },
      { id: '1-2', label: 'Open' },
    ],
  },
  {
    id: '2',
    label: 'Edit',
    backgroundColor: '#10b981',
    selectedColor: '#34d399',
    hoverColor: '#059669',
    badgeConfig: {
      backgroundColor: '#f59e0b',
      textColor: '#ffffff',
      size: 20,
      fontSize: 12,
      show: true,
    },
    children: [
      { id: '2-1', label: 'Cut' },
      { id: '2-2', label: 'Copy' },
    ],
  },
];

<RadialMenu items={menuItems} />

Color Inheritance:

  • If an item doesn't specify colors, it falls back to global colors
  • Children inherit their parent's custom colors (selectedColor, hoverColor, badgeConfig)
  • Individual children can override inherited colors by specifying their own

Auto Gradient

Enable automatic gradient generation for submenus. When enabled, each submenu level gets a lighter shade of its parent's color, creating a cohesive visual hierarchy.

<RadialMenu
  items={menuItems}
  autoGradient={true}
  gradientLightnessRange={20}
  gradientSaturationRange={10}
/>

With autoGradient enabled:

  • Level 0 (main menu): Uses the specified backgroundColor or default color
  • Level 1 (submenu): Automatically lighter shade of parent color
  • Each submenu level progressively gets lighter while maintaining the same color tone

Gradient Customization:

  • gradientLightnessRange (default: 20): Controls how much lighter the colors become (0-50%)
    • Higher values create stronger contrast between items
    • Lower values create more subtle transitions
  • gradientSaturationRange (default: 10): Controls saturation variation (0-30%)
    • Higher values create more vibrant progressions
    • Lower values maintain consistent saturation

This creates a beautiful, harmonious color scheme without manual configuration.

Animation Presets

<RadialMenu
  items={items}
  animationPreset="smooth"
  animationDuration={400}
/>

Available presets:

  • 'fast' - Quick, snappy animations
  • 'smooth' - Balanced, smooth transitions
  • 'elastic' - Bouncy, playful animations
  • 'slow' - Gentle, slow-motion animations
  • 'none' - No animations

TypeScript Support

This library is written in TypeScript and provides full type definitions. All types are exported from the main package:

import type {
  RadialMenuItem,
  RadialMenuColors,
  RadialMenuPosition,
  RadialMenuConfig,
  SelectedItems,
  BadgeConfig,
  AnimationPreset,
} from '@crocogiciel/react-web-radial-menu';

Color Behavior

Custom Colors

  • Each menu item can have custom properties:
    • backgroundColor - Base color for the item
    • selectedColor - Color when the item is selected
    • hoverColor - Color when hovering over the item
    • badgeConfig - Custom badge styling for this item
  • If not specified, items use the default colors from the global color scheme
  • Children inherit their parent item's custom colors by default
  • Individual children can override inherited colors

Auto Gradient

  • When autoGradient is enabled, submenus automatically receive lighter shades of their parent's color
  • The gradient algorithm adjusts both lightness and saturation to maintain visual harmony
  • Customizable with gradientLightnessRange (default: 20%) and gradientSaturationRange (default: 10%)
  • Each submenu item becomes progressively lighter in a clockwise direction
  • The gradient stays within the same color tone for consistency
  • Works with both default colors and custom per-item colors

Behavior

Selection

  • Click on any item without children to select/deselect it
  • Items with children will open a submenu when clicked
  • Selected items are highlighted with the configured selection color
  • A count of selected items is displayed in the center

Validation

  • Click the checkmark button in the center to validate the selection
  • Click outside the menu to automatically validate and close
  • The onValidate callback receives an array of selected item IDs

Cancellation

  • Click the X button in the center to cancel without validating
  • The onCancel callback is triggered
  • No selection is saved

Demo

Check out the live demo to see the radial menu in action with all its features.

You can view the demo source code here.

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Repository

https://github.com/crocogiciel/react-web-radial-menu