Sound Usage & Choreography

Hierarchy, pairing open/close sounds, directional navigation, and notification tiers: applied Material choreography for sensory-ui.

How to combine sounds across a flow so the interface feels coherent. Adapted from Sound choreography and Applying sound to UI.

Hierarchy: one foreground sound at a time

LevelRolesCharacter
Foregroundnotification.*, hero.*Longer (200–1900ms), carry meaning alone
Middlegroundoverlay.*, navigation.*40–270ms, structural
Backgroundinteraction.*8–50ms transients, felt more than heard

Rules:

  1. Never play two foreground sounds together. Queue or pick the most important.
  2. A foreground sound suppresses background ticks (e.g. success toast after submit: play notification.success, skip the button tap).
  3. hero.* is disabled by default (double opt-in: enable category + set sound prop).

Pairing: open ↔ close, expand ↔ collapse

From Sound choreography: paired actions should be tonal inversions: same voice, opposite arc.

OpenCloseComponents
overlay.openoverlay.closeDialog, Sheet, Popover, Select
overlay.expandoverlay.collapseAccordion, Collapsible
navigation.forwardnavigation.backwardCarousel, Pagination
// Overlay pattern: two props, one pair
<Dialog sound="overlay.open" closeSound="overlay.close">
  ...
</Dialog>

// Expand pattern
<Accordion expandSound="overlay.expand" collapseSound="overlay.collapse">
  ...
</Accordion>

Don't mix pairs (e.g. overlay.open with overlay.collapse). Keep the metaphor consistent.

Directional navigation

  • Forward / next / right → navigation.forward (rising sweep)
  • Back / previous / left → navigation.backward (falling sweep, mirror of forward)
  • Lateral switch with no direction → navigation.tab (short pop)

Notification tiers

Material use cases distinguish info vs. success vs. warning vs. error by intensity:

RoleShapeWhen
notification.infoSingle soft chimePassive update, FYI toast
notification.successThree ascending notes (C5–E5–G5)Saved, completed, validated
notification.warningTwo-note semitone ascent (A4 → A♯4)Quota, confirm-needed, destructive preview
notification.errorFiltered descending sweep (320 → 140 Hz)Failed, disconnected, invalid

Don't upgrade info to success for emphasis. Frequency of success sounds dilutes them.

Attributes: pitch, timbre, loudness

From Sound attributes:

  • Pitch: higher = lighter / smaller; lower = heavier / consequential. Destructive actions (notification.warning) sit lower than confirmations.
  • Timbre: pick one pack per app and stick with it. Timbre is brand.
  • Loudness: keep master 0.3–0.4; use per-component volume to push secondary actions down, never to push primary actions above the ceiling.

Anti-patterns

Don'tWhyDo instead
Sound on every hoverFatigue, no user intentSound on click / commit only
Different tap per buttonBreaks consistencyOne interaction.tap everywhere, interaction.confirm for submits
Hero sound per session stepCelebration inflationhero.complete once per milestone
Auto-play on mountBlocked by browsers, surprises usersTrigger from click / keyboard only
Sound without visual changeInaccessiblePair every cue with visible state

Worked example: checkout flow

// 1. Shipping form: rewarded submit, not a plain tap
<Button sound="interaction.confirm">Continue to payment</Button>

// 2. Confirm dialog: paired open/close, no stacked button sound
<Dialog sound="overlay.open" closeSound="overlay.close">...</Dialog>

// 3. Payment success: foreground success suppresses the button tick
playSound("notification.success"); // skip the tap underneath

// 4. Order placed: the one moment worthy of a hero sound
playSound("hero.complete"); // categories.hero must be enabled

Each step uses exactly one foreground sound. Compare with the taste rules and see it composed in the Timer + Confetti block.

Reference