Sound

Getting Started

Sound

Opt-in interaction sounds from Cuelume. Off by default, one prop per component or one switch for the whole app.

goopUI can play short interaction sounds through Cuelume: a tap for a button, a snap for a switch, a soft whoosh when a dialog opens. The sounds are synthesized with Web Audio, so there are no audio files to ship.

Sound is off by default. Until you turn it on, components render exactly the same markup as before and Cuelume is never loaded.

Install Cuelume

Cuelume is an optional peer dependency of @goopui/core. Install it in your app:

pnpm add cuelume

It's only imported, lazily and in the browser, once sound is on. If sound is on and Cuelume isn't installed, nothing plays and you get one warning in the console.

Turn it on

For one component, add the sound prop:

<GoopButton sound>Save</GoopButton>
<GoopSwitch sound />

On a root component, sound covers its parts too. A sounding GoopDialog makes its trigger and close buttons sound, and a sounding GoopSelect makes its trigger and items sound:

<GoopDialog sound>
  <GoopDialogTrigger as-child>
    <GoopButton>Open</GoopButton>
  </GoopDialogTrigger>
  <GoopDialogContent>…</GoopDialogContent>
</GoopDialog>

For the whole app in Nuxt, set goop.sound:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@goopui/nuxt'],
  goop: { sound: true },
})

Without Nuxt, pass sound to the plugin, or set it for part of the tree with provideGoopSound:

app.use(GoopPlugin, { sound: true })
// in a parent component's setup
provideGoopSound(true)

A component's own sound prop always wins, so <GoopButton :sound="false"> stays quiet in a sounding app.

Muting

@goopui/core holds one switch for playback. Wire it to your own sound toggle:

import { disableSound, enableSound, isSoundEnabled } from '@goopui/core'

enableSound()  // load Cuelume, bind its listeners, unmute
disableSound() // mute: later cues are silent, ringing ones fade

Once you've called disableSound(), components with sound keep their markup but stay silent until you call enableSound() again. Browsers only start audio after someone has interacted with the page, so call enableSound() from the click that turns sound on.

Which sound plays

Each component plays the cue for its job, following Cuelume's guidance. Nothing plays on hover, so tooltips and hover cards stay silent.

ComponentCue
Button, Alert dialog actiontap
Switch, Checkbox, Toggle, menu checkbox itemstoggle
Radio group items, Toggle group items, Tabs triggersselect
Select, Dropdown menu, Context menu, Combobox and Command itemsselect (Command items subtle)
Select trigger, Dropdown menu trigger, submenu triggers, Combobox triggeropen, subtle
Popover, Accordion and Collapsible triggersopen / close, subtle
Dialog, Alert dialog, Sheet, Drawer triggersopen
Dialog, Sheet, Drawer close buttons, Alert dialog cancelclose
Number field steppersselect, subtle
Input, Textarea, Input OTP, Combobox inputtype (never on password fields)
Toasterthe toast's outcome, subtle: success, error, warning, loading, and ready for info and plain toasts

The map lives in @goopui/core as GOOP_SOUND_CUES (and GOOP_TOAST_CUES for toasts), so every framework adapter plays the same cues. To play an outcome yourself, use playCue. It does nothing while sound is off:

import { playCue } from '@goopui/core'

playCue('success', { emphasis: 'subtle' })

Sound is not motion

prefers-reduced-motion doesn't change sound, and turning sound off doesn't change the goo. Someone who turns off animation may still want sound, so each one has its own switch.