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

volca-drum-ui

v0.1.3

Published

Lightweight, accessible React component library designed for Figma Make integration

Downloads

407

Readme

@midi-volca-drum/ui-components

A lightweight, accessible React component library designed for Figma Make integration

npm version License: MIT

Overview

A collection of production-ready React components extracted from the MIDI Volca Drum Editor project. Designed with Figma Make in mind, these components bridge the gap between design and code, making it easy to use production components in your Figma prototypes.

Key Features

  • 🎨 Figma Make Ready - Designed to work seamlessly with Figma Make
  • Accessible - WCAG 2.1 compliant with proper ARIA labels
  • 🎹 Keyboard Navigation - Full keyboard support for all interactive components
  • 🌗 Theme Support - CSS custom properties for easy theming
  • 📦 Lightweight - ~8KB JS + ~13KB CSS (gzipped)
  • Tree-shakeable - Import only what you need
  • 🔒 TypeScript - Full type definitions included

Installation

npm install @midi-volca-drum/ui-components

Peer Dependencies

This library requires React 18 or higher:

npm install react@^18.0.0 react-dom@^18.0.0

Quick Start

import { Button, Slider, Modal } from '@midi-volca-drum/ui-components';
import '@midi-volca-drum/ui-components/styles';

function App() {
  const [value, setValue] = useState(64);

  return (
    <>
      <Button variant="primary" onClick={() => console.log('Clicked!')}>
        Click Me
      </Button>

      <Slider
        id="volume"
        label="Volume"
        value={value}
        onChange={setValue}
        min={0}
        max={127}
      />
    </>
  );
}

Components

Accordion

Collapsible content sections with smooth animations.

import { Accordion } from '@midi-volca-drum/ui-components';

<Accordion
  id="my-accordion"
  title="Settings"
  defaultExpanded={true}
  direction="vertical"
>
  <p>Your content here</p>
</Accordion>

Props:

  • id (string, required) - Unique identifier
  • title (string, required) - Header text
  • defaultExpanded (boolean) - Initial state (default: true)
  • direction ('vertical' | 'horizontal') - Collapse direction (default: 'vertical')
  • className (string) - Additional CSS classes
  • children (ReactNode) - Content to collapse/expand

Button

Versatile button component with multiple variants.

import { Button } from '@midi-volca-drum/ui-components';

<Button variant="primary" size="medium" onClick={handleClick}>
  Click Me
</Button>

Props:

  • variant ('primary' | 'secondary' | 'text') - Visual style (default: 'primary')
  • size ('small' | 'medium' | 'large') - Button size (default: 'medium')
  • disabled (boolean) - Disabled state
  • type ('button' | 'submit' | 'reset') - HTML button type
  • children (ReactNode, required) - Button content
  • All standard HTML button attributes

Modal

Accessible modal dialog with backdrop.

import { Modal } from '@midi-volca-drum/ui-components';

<Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Settings">
  <p>Modal content goes here</p>
</Modal>

Props:

  • isOpen (boolean, required) - Visibility state
  • onClose (function, required) - Close handler
  • title (string, required) - Modal title
  • children (ReactNode, required) - Modal content

RadioButton & RadioGroup

Radio button inputs with icon or text variants.

import { RadioGroup } from '@midi-volca-drum/ui-components';

const options = [
  { id: 'option1', value: '1', label: 'Option 1' },
  { id: 'option2', value: '2', label: 'Option 2' },
  { id: 'option3', value: '3', label: 'Option 3' },
];

<RadioGroup
  name="my-radio-group"
  options={options}
  value={selectedValue}
  onChange={setSelectedValue}
/>

RadioGroup Props:

  • name (string, required) - Radio group name
  • options (RadioOption[], required) - Array of radio options
  • value (string | number, required) - Selected value
  • onChange (function, required) - Change handler
  • className (string) - Additional CSS classes
  • disabled (boolean) - Disabled state

RadioOption:

  • id (string, required) - Unique identifier
  • value (string | number, required) - Option value
  • label (string, required) - Display label
  • imageSrc (string) - Icon image URL (for icon variant)
  • imageAlt (string) - Icon alt text
  • variant ('icon' | 'text') - Display style (default: 'text')
  • disabled (boolean) - Disabled state

Slider

Range input with visual feedback and custom formatting.

import { Slider } from '@midi-volca-drum/ui-components';

<Slider
  id="volume"
  label="Volume"
  value={volume}
  onChange={setVolume}
  min={0}
  max={127}
  step={1}
  formatValue={(v) => `${v}%`}
/>

Props:

  • id (string, required) - Unique identifier
  • label (string, required) - Slider label
  • value (number, required) - Current value
  • onChange (function, required) - Change handler: (value: number) => void
  • min (number) - Minimum value (default: 0)
  • max (number) - Maximum value (default: 127)
  • step (number) - Step increment (default: 1)
  • formatValue (function) - Custom value formatter: (value: number) => string
  • className (string) - Additional CSS classes
  • disabled (boolean) - Disabled state

Switch

Toggle switch for boolean settings.

import { Switch } from '@midi-volca-drum/ui-components';

<Switch
  id="dark-mode"
  label="Dark Mode"
  checked={isDarkMode}
  onChange={() => setIsDarkMode(!isDarkMode)}
/>

Props:

  • id (string, required) - Unique identifier
  • label (string, required) - Switch label
  • checked (boolean, required) - Current state
  • onChange (function, required) - Toggle handler: () => void
  • disabled (boolean) - Disabled state

Toast

Toast notifications for user feedback. This component wraps react-hot-toast with styled defaults.

import { toast } from '@midi-volca-drum/ui-components';

// Success toast
toast.success('Settings saved successfully!');

// Error toast
toast.error('Failed to connect to device');

// Info toast
toast('Processing your request...');

// Custom duration
toast.success('File uploaded', { duration: 5000 });

// With custom ID (prevents duplicates)
toast.success('Connection established', { id: 'midi-connect' });

Toast API:

  • toast(message, options?) - Default toast
  • toast.success(message, options?) - Success toast with green indicator
  • toast.error(message, options?) - Error toast with red indicator
  • toast.loading(message, options?) - Loading toast with spinner
  • toast.custom(component, options?) - Custom toast component
  • toast.dismiss(toastId?) - Dismiss specific or all toasts

Common Options:

  • duration (number) - Display duration in ms (default: 4000)
  • position ('top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right') - Toast position
  • id (string) - Unique ID to prevent duplicate toasts
  • icon (ReactNode) - Custom icon
  • style (CSSProperties) - Custom inline styles

Note: The Toast component uses react-hot-toast under the hood. You can import Toaster to customize the toast container:

import { Toaster } from 'react-hot-toast';

function App() {
  return (
    <>
      <Toaster position="top-right" />
      {/* Your app content */}
    </>
  );
}

Theming & Customization

All components use CSS custom properties (CSS variables) for styling, making them fully themeable without modifying component code.

Theme Switching

The library supports multiple themes using the data-theme attribute approach. By default, components use dark theme colors. Override with light theme by setting data-theme="light" on the root element:

// Example theme switcher component
function ThemeToggle() {
  const [isDark, setIsDark] = useState(true);

  const toggleTheme = () => {
    if (isDark) {
      document.documentElement.dataset.theme = 'light';
    } else {
      delete document.documentElement.dataset.theme;
    }
    setIsDark(!isDark);
  };

  return (
    <button onClick={toggleTheme}>
      {isDark ? 'Switch to Light' : 'Switch to Dark'}
    </button>
  );
}

Custom Theme Example

Create your own theme by defining CSS variables:

/* Dark theme (default) */
:root, :root:not([data-theme="light"]) {
  --color-background-app: #141a24;
  --color-background-elevated: #0f141f;
  --color-text-title: #b2bfcc;
  --color-text-subtitle: #99a6b2;
  --color-stroke-cyan: #00b2f2;
}

/* Light theme */
:root[data-theme="light"] {
  --color-background-app: #ffffff;
  --color-background-elevated: #f8f9fa;
  --color-text-title: #212529;
  --color-text-subtitle: #495057;
  --color-stroke-cyan: #00b2f2;
}

/* Custom brand theme */
:root[data-theme="brand"] {
  --color-stroke-cyan: #ff6b35;  /* Custom accent color */
  --color-stroke-green: #4ecdc4;
  --color-stroke-orange: #f7931e;
}

Complete CSS Custom Properties Reference

Colors - Background

--color-background-app          /* Main app background */
--color-background-elevated     /* Elevated surfaces (cards, modals) */
--color-background-container    /* Container backgrounds */
--color-background-card         /* Card backgrounds */
--color-background-object       /* UI object backgrounds */
--color-background-hover        /* Hover state background */
--color-bg-surface              /* Surface backgrounds */
--color-bg-base                 /* Base layer background */

Colors - Text

--color-text-active             /* Active/selected text */
--color-text-title              /* Title text */
--color-text-body               /* Body text */
--color-text-subtitle           /* Subtitle text */
--color-text-muted              /* Muted/secondary text */
--color-text-disabled           /* Disabled text */

Colors - Stroke/Accent

--color-stroke-green            /* Success/green accent */
--color-stroke-green-overlay    /* Green overlay/background */
--color-stroke-cyan             /* Primary/cyan accent */
--color-stroke-cyan-overlay     /* Cyan overlay/background */
--color-stroke-orange           /* Warning/orange accent */
--color-stroke-orange-overlay   /* Orange overlay/background */
--color-stroke-neutral          /* Neutral borders/strokes */

Colors - Buttons

--color-button-status-default   /* Status button default */
--color-button-primary-default  /* Primary button default */
--color-button-primary-hover    /* Primary button hover */
--color-button-secondary-default /* Secondary button default */
--color-button-secondary-hover  /* Secondary button hover */

Colors - Other

--color-input-background        /* Input field backgrounds */
--color-error-default           /* Error state color */
--color-error-background        /* Error background */

Spacing

--spacing-xxs: 8px
--spacing-xs: 10px
--spacing-s: 12px
--spacing-m: 16px
--spacing-l: 20px
--spacing-xl: 24px
--spacing-xxl: 32px
--spacing-xxxl: 48px

Border Radius

--border-radius-s: 6px
--border-radius-m: 8px
--border-radius-l: 12px
--border-radius-xl: 20px

Typography

/* Display */
--font-display-lg-size: 20px
--font-display-lg-weight: 700
--font-display-lg-line-height: 1.4
--font-display-lg-letter-spacing: -0.01em

/* Headings */
--font-heading-lg-size: 16px
--font-heading-lg-weight: 700
--font-heading-md-size: 14px
--font-heading-md-weight: 700
--font-heading-sm-size: 12px
--font-heading-sm-weight: 700

/* Body */
--font-body-lg-size: 16px
--font-body-lg-weight: 600
--font-body-md-size: 13px
--font-body-md-weight: 600
--font-body-sm-size: 12px
--font-body-sm-weight: 600

/* Labels */
--font-label-md-size: 12px
--font-label-md-weight: 700
--font-label-md-line-height: 1.4
--font-label-md-letter-spacing: 0.02em

/* Caption */
--font-caption-size: 10px
--font-caption-weight: 600
--font-caption-line-height: 1.4
--font-caption-letter-spacing: 0.02em

/* Font Family */
--font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif

Persistence

Theme preference can be persisted using localStorage:

function useTheme() {
  const [theme, setTheme] = useState(() => {
    return localStorage.getItem('theme') || 'dark';
  });

  useEffect(() => {
    if (theme === 'light') {
      document.documentElement.dataset.theme = 'light';
    } else {
      delete document.documentElement.dataset.theme;
    }
    localStorage.setItem('theme', theme);
  }, [theme]);

  return { theme, setTheme };
}

Figma Make Integration

This library is specifically designed to work with Figma Make. Follow these steps to integrate:

  1. Install the library in your project
  2. Import components in your Figma Make setup
  3. Use production components in your Figma prototypes instead of mockups

See /docs/figma-make-setup.md for detailed integration guide.

Development

Setup

# Install dependencies
npm install

# Build library
npm run build

# Watch mode for development
npm run dev

# Type checking
npm run type-check

# Linting
npm run lint
npm run lint:fix

Project Structure

src/
├── components/
│   ├── Accordion/
│   │   ├── Accordion.tsx
│   │   ├── Accordion.css
│   │   └── index.ts
│   ├── Button/
│   ├── Modal/
│   └── ...
├── styles/
│   └── index.css
└── index.ts

Building

The library is built using Vite in library mode:

npm run build

Output:

  • dist/index.js - ES module bundle
  • dist/index.d.ts - TypeScript declarations
  • dist/style.css - Component styles

Browser Support

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+

Contributing

Contributions are welcome! This library was extracted from the MIDI Volca Drum Editor project.

Guidelines

  1. Follow existing code style
  2. Add TypeScript types for all props
  3. Include CSS with each component
  4. Test accessibility (keyboard navigation, ARIA labels)
  5. Keep components generic (no app-specific logic)

License

MIT © Hans Desmedt

Related Projects

Support

For issues and questions: