Skip to content

About

⏱️✨ Luxury watchmaker-inspired concentric rotary FAB & precision arc dial component for React with multi-tier orbital physics, 8 animation modes, and tactile haptics.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

 
 

Repository files navigation

react-rotary-fab logo

react-rotary-fab ⏱✨

A luxury watchmaker-inspired, highly customizable concentric rotary Floating Action Button (FAB) and precision Rotary Arc Dial / Slider for React.

npm version Documentation & Demo license bundle size TypeScript


🌟 Highlights

  • ⏱ Concentric Multi-Tier Orbital Arcs: Distribute 4, 9, or 20+ action items across balanced concentric arc tiers with smooth staggered entrance physics.
  • 🧭 4-Corner & Edge Quadrant Math: Automatic trigonometric coordinate mapping for bottom-left, bottom-right, top-left, and top-right.
  • 🎛 6 Precision Dial Design Styles: watchmaker (classic horology), minimal, cyber-segmented, neon-glow, retro-analog, and holographic.
  • 🎨 6 Built-in Themes: luxury-watch (OLED obsidian & jewels), 3d (tactile skeuomorphic push), glassmorphic (frosted crystal), cyberpunk (laser HUD), minimal-light (porcelain), and neon (ultra-violet).
  • 📳 Tactile Haptic Feedback Engine: Safe Web Vibration API engine with realistic tactile patterns (tick, light, medium, boundary, danger, toggle).
  • 🌌 Studio Corner Ambient Backlighting: High-end radial, aurora, and neon corner ambient glow modes.
  • 💅 Full CSS Variable Customization: Customize colors, glows, blur, backdrop, and sizes with CSS variables or Tailwind.
  • 🛡 Zero Heavy UI Dependencies: Completely standalone — includes built-in accessible tooltips, badge counts, and notifications with zero bundle bloat.
  • ♿ Full Accessibility: Keyboard arrow controls (ArrowUp/Down/Left/Right, PageUp/Down, Home/End), mouse wheel support, and WCAG-compliant ARIA attributes.
  • 📦 100% TypeScript: Comprehensive type definitions and JSDoc annotations.

📦 Installation

npm install react-rotary-fab
# or
yarn add react-rotary-fab
# or
pnpm add react-rotary-fab

Import the stylesheet in your root entry file (App.tsx or index.tsx):

import 'react-rotary-fab/styles.css';

🚀 Quick Start

import React, { useState } from 'react';
import { RotaryFab, Icons } from 'react-rotary-fab';
import 'react-rotary-fab/styles.css';

export default function App() {
  const [volume, setVolume] = useState(70);
  const [isPlaying, setIsPlaying] = useState(false);
  const [isDialMode, setIsDialMode] = useState(false);

  const items = [
    // Tier 0: Quick Actions
    {
      id: 'vol',
      title: 'Precision Volume Dial',
      icon: <Icons.Volume />,
      onClick: () => setIsDialMode(true)
    },
    {
      id: 'play',
      title: isPlaying ? 'Pause' : 'Play',
      icon: isPlaying ? <Icons.Pause /> : <Icons.Play />,
      active: isPlaying,
      onClick: () => setIsPlaying(p => !p)
    },
    {
      id: 'mic',
      title: 'Microphone',
      icon: <Icons.MicOn />,
      danger: false
    },
    {
      id: 'settings',
      title: 'Settings',
      icon: <Icons.Settings />,
      hasBadge: true,
      onClick: () => console.log('Opened settings')
    }
  ];

  return (
    <div className="app-container">
      <RotaryFab
        items={items}
        placement="bottom-left"
        theme="luxury-watch"
        enableHaptics={true}
        dialMode={isDialMode}
        onDialModeChange={setIsDialMode}
        dialProps={{
          value: volume,
          min: 0,
          max: 100,
          step: 1,
          unit: '% VOL',
          onChange: setVolume
        }}
      />
    </div>
  );
}

🎛 Using the Standalone RotaryDial

You can also use the high-precision rotary arc slider anywhere as an independent component:

import React, { useState } from 'react';
import { RotaryDial } from 'react-rotary-fab';

export function BrightnessControl() {
  const [brightness, setBrightness] = useState(80);

  return (
    <RotaryDial
      value={brightness}
      min={0}
      max={100}
      step={1}
      radius={130}
      placement="bottom-left"
      unit="% LUX"
      onChange={setBrightness}
      showTicks={true}
      showMicroDots={true}
      showNeedle={true}
      showGlow={true}
      enableHaptics={true}
    />
  );
}

📖 API Reference

<RotaryFab /> Props

Prop Type Default Description
items RotaryFabItem[] [] Array of action menu items distributed across concentric arcs.
placement FabPlacement 'bottom-left' Corner or edge placement ('bottom-left', 'bottom-right', 'top-left', 'top-right', 'bottom-center', 'top-center', 'center').
theme FabTheme 'luxury-watch' Preset theme ('luxury-watch', 'glassmorphic', 'cyberpunk', 'minimal-light', 'neon').
animationMode AnimationMode 'spring' Animation mode: 'spring', 'stagger', 'spiral', 'fan', 'scale', 'elastic', 'fade', 'none'.
customTheme Record<string, string> undefined Custom CSS variable overrides.
open boolean undefined Controlled open/expanded state.
defaultOpen boolean false Uncontrolled default open state.
onOpenChange (open: boolean) => void undefined Callback fired when open state changes.
dialMode boolean undefined Controlled rotary dial/slider mode state.
defaultDialMode boolean false Uncontrolled default dial mode state.
onDialModeChange (isDial: boolean) => void undefined Callback fired when dial mode is toggled.
dialProps Partial<RotaryDialProps> {} Options passed to the embedded rotary dial.
arcConfigs ArcTierConfig[] [tier0, tier1, tier2] Custom radii and button sizes for concentric tiers.
mainButtonSize number 52 Diameter of the main floating action button in pixels.
mainButton ReactNode | ((state) => ReactNode) undefined Custom render for the main FAB button.
mainButtonIcon ReactNode <Icons.Menu /> Custom closed icon.
mainButtonCloseIcon ReactNode <Icons.Close /> Custom open/expanded icon.
mainButtonDialIcon ReactNode <Icons.Back /> Custom dial mode active icon.
autoCollapseTimeout number | null 9500 Inactivity timer (in ms) to auto-collapse the menu. Set to null to disable.
closeOnItemClick boolean true Auto-close menu when an item is clicked.
closeOnOutsideClick boolean true Auto-close when clicking outside.
enableHaptics boolean true Enable safe tactile vibration on supported devices.
showOrbitLines boolean true Enable or disable concentric dashed SVG orbit guidelines.
showCornerBackdrop boolean true Show ambient radial gradient corner backdrop.
renderItem (item, index, tier) => ReactNode undefined Custom item renderer function.

RotaryFabItem Interface

interface RotaryFabItem {
  id: string;                                          // Unique identifier
  title?: string;                                      // Tooltip and accessible title
  icon?: React.ReactNode;                              // Icon element
  children?: React.ReactNode;                          // Custom button inner content
  onClick?: (event: React.MouseEvent) => void;         // Click handler
  active?: boolean;                                    // Active / highlighted state
  danger?: boolean;                                    // Danger / destructive action styling
  disabled?: boolean;                                  // Disabled state
  hasBadge?: boolean | string | number;                // Indicator dot or numerical count badge
  badgeColor?: string;                                 // Custom badge color
  tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right' | 'auto'; // Tooltip direction
  ariaLabel?: string;                                  // Accessible ARIA label
  className?: string;                                  // Custom CSS class
  style?: React.CSSProperties;                         // Custom inline styles
  tier?: number;                                       // Explicit tier override (0 = innermost)
  haptic?: HapticType;                                 // Custom haptic pattern on click
}

<RotaryDial /> Props

Prop Type Default Description
value number undefined Controlled value.
defaultValue number 50 Uncontrolled default value.
min number 0 Minimum value.
max number 100 Maximum value.
step number 1 Increment step.
radius number 124 Radius of the dial arc in pixels.
placement FabPlacement 'bottom-left' Corner placement.
unit string '% VOL' Unit suffix displayed in the chrono readout badge.
label string | ((val) => ReactNode) undefined Custom readout formatter.
showTicks boolean true Render precision watch tick marks.
tickCount number 20 Number of discrete tick marks.
showMicroDots boolean true Render inner celestial micro-dot orbit.
showNeedle boolean true Render watch dial needle on thumb.
showGlow boolean true Enable glowing drop-shadow filters.
enableHaptics boolean true Enable physical step haptics while dragging.
onChange (value: number) => void undefined Callback fired on continuous dragging/scrubbing.
onChangeEnd (value: number) => void undefined Callback fired when user releases pointer.

🎨 Theming & CSS Variables

You can customize every aspect of the FAB using CSS variables:

:root {
  --rf-bg-main: linear-gradient(135deg, #18191c 0%, #0d0e11 100%);
  --rf-bg-item: rgba(24, 25, 29, 0.88);
  --rf-bg-item-hover: rgba(42, 44, 52, 0.96);
  --rf-bg-item-active: #ffffff;
  --rf-border: rgba(255, 255, 255, 0.18);
  --rf-text: #ffffff;
  --rf-text-muted: rgba(255, 255, 255, 0.55);
  --rf-accent: #38bdf8;
  --rf-accent-glow: rgba(56, 189, 248, 0.75);
  --rf-danger: #ef4444;
  --rf-danger-glow: rgba(239, 68, 68, 0.7);
  --rf-track: rgba(255, 255, 255, 0.15);
  --rf-fill: #38bdf8;
  --rf-shadow: 0 8px 32px rgba(0, 0, 0, 0.65);
  --rf-tooltip-bg: #0f1013;
  --rf-tooltip-text: #ffffff;
}

Or pass customTheme directly to the component:

<RotaryFab
  items={items}
  customTheme={{
    '--rf-accent': '#10b981',
    '--rf-accent-glow': 'rgba(16, 185, 129, 0.8)'
  }}
/>

⌨️ Accessibility & Controls

Input Action
Pointer / Touch Drag Smooth circular scrubbing with physical step snapping
ArrowUp / ArrowRight Increment value by step
ArrowDown / ArrowLeft Decrement value by step
PageUp / PageDown Increment / decrement by large step (5 * step)
Home / End Snap directly to min / max
Mouse Wheel Increment / decrement when hovering dial
Space / Enter Toggle button activation

👥 Contributors

nikhileashy
Nikhil Eashy

💻 Code, Architecture & Development
neehanazer
Neeha Nazer

🎨 Design, Aesthetics & Concept Contribution

🤝 Contributing

Contributions are welcome! Please check out CONTRIBUTING.md for details on setting up the development environment, running tests, and opening pull requests.


📄 License

MIT © Nikhil Eashy

About

⏱️✨ Luxury watchmaker-inspired concentric rotary FAB & precision arc dial component for React with multi-tier orbital physics, 8 animation modes, and tactile haptics.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages