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.
| Component | Cue |
|---|---|
| Button, Alert dialog action | tap |
| Switch, Checkbox, Toggle, menu checkbox items | toggle |
| Radio group items, Toggle group items, Tabs triggers | select |
| Select, Dropdown menu, Context menu, Combobox and Command items | select (Command items subtle) |
| Select trigger, Dropdown menu trigger, submenu triggers, Combobox trigger | open, subtle |
| Popover, Accordion and Collapsible triggers | open / close, subtle |
| Dialog, Alert dialog, Sheet, Drawer triggers | open |
| Dialog, Sheet, Drawer close buttons, Alert dialog cancel | close |
| Number field steppers | select, subtle |
| Input, Textarea, Input OTP, Combobox input | type (never on password fields) |
| Toaster | the 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.