Sounded is a lightweight, theme-aware sound system for React and Next.js apps. It provides subtle UI feedback using hover and click sounds, with full support for dark/light themes, mute toggles, and accessibility-friendly enhancements.
- Provides global configuration for UI sound effects
- Cleanly integrates with React components using a simple
<Sounded>wrapper - Enables dark/light themeβspecific sound sets
- Global mute toggle with persistence
- One-shot AudioContext support
- Offers a persistent mute toggle with
localStoragesupport - Works with any interactive component (
button,div,a, etc.) - Fast, typed, and Tailwind-compatible
- Works seamlessly in Next.js App Router
- Minimal runtime overhead
- Requires client-only usage (
'use client') - Not SSR-compatible (by design)
- Must wrap interactive elements manually (or abstract with design system)
npm install plebs/sounded
or with yarn:
yarn add plebs/sounded
Then import components and hooks directly from the package:
import { SoundedProvider, useSoundedContext, useSound, Sounded } from 'plebs/sounded';
Wrap your app in this provider to enable sound context features:
import { SoundedProvider } from 'plebs/sounded'; <SoundedProvider theme="dark"> <App /> </SoundedProvider>
theme:"light"|"dark"β determines which sound pack to use- Stores the
mutedstate inlocalStorageautomatically
Use this hook anywhere in your app to access or control the sound system:
const { muted, toggleMute, sounds, theme } = useSoundedContext();
Wraps any UI element and injects sound on hover or click automatically:
<Sounded> <button>Hover and click sound</button> </Sounded> <Sounded sound={false}> <button>No sound button</button> </Sounded> <Sounded hoverSound={false}> <div>Hover sound disabled</div> </Sounded> <Sounded overrideHover="/custom/hover.mp3"> <div>Hover here</div> </Sounded> <Sounded overrideClick="/custom/click.mp3"> <a href="#">Custom click sound</a> </Sounded>
| Prop | Type | Description |
|---|---|---|
overrideClick |
string |
Optional custom sound file for click events |
overrideHover |
string |
Optional custom sound file for hover events |
sound |
boolean |
Set to false to disable all sound |
clickSound |
boolean |
Set to false to disable only click sound |
hoverSound |
boolean |
Set to false to disable only hover sound |
A lower-level hook for custom playback use cases:
const play = useSound(['/sounds/ping.mp3']); <button onClick={play}>Custom Trigger</button>
You can pass an optional second argument to useSound(urls, options):
const play = useSound(['/sounds/ping.mp3'], { fallbackToSilence: true, // fallback to silent buffer if all sounds fail onLoadError: (url, error) => { console.error(`Failed to load sound from ${url}:`, error); }, });
- If all sounds fail to load or decode, a 1-frame silent buffer will be used to avoid crashes.
- If set to
false, an error will be thrown instead.
- A callback function that is invoked when a sound fails to fetch or decode.
- Useful for analytics, debugging, or alerting.
- Place your sound files in
/public/sounds/ - Update
soundMapinsideSoundedContext.tsx:
const soundMap = { dark: { click: '/sounds/dark-click.mp3', hover: '/sounds/dark-hover.mp3', }, light: { click: '/sounds/light-click.mp3', hover: '/sounds/light-hover.mp3', }, };
- Enhanced web apps with rich UIs
- Accessible audio feedback systems
- Design systems that support multimodal interaction
- Games, dashboards, or web-based experiences with hover/click feedback
- Keep sounds subtle and under 500ms
- Use low-pass or analog-style tones to avoid fatigue
- Offer mute toggle visibly or inside user settings
- Use
<Sounded>consistently for accessibility parity
/src
/context
SoundedContext.tsx # Global state and provider
/hooks
useSound.ts # Playback logic
/components
Sounded.tsx # Wrapper component for sound-enabled elements
For bugs, ideas, or enhancements, please reach out or fork this module.