HomeProjectsBlogContact
~/Blog

Want to chat? root.vewake@gmail.com

© 2026 Vivek Patil

~/Blog
Jun 2026
4 min read

Crafting micro-interactions with Web Audio


Giving Web Interfaces a Sense of Touch

Web applications have historically been strangely silent.

Desktop operating systems and classic terminal environments have long used tiny auditory cues to acknowledge actions. A key press, a notification, a system error, or even a simple toggle can produce a barely noticeable sound that tells you, without looking, that something happened.

The web rarely does this well.

But that doesn't mean it has to stay that way.

With the browser's native Web Audio API, interfaces can generate small, responsive sounds directly in the browser. No MP3 library, no collection of audio files, and no extra assets to manage.

I recently added this idea to my own site using Cuelume, a small library for synthesized interaction sounds.

Why Add Sound to a Website?#

Sound is an interesting form of feedback because it doesn't compete for the same attention as the visual interface.

A button can change color.

A modal can animate.

A notification can appear.

But a tiny sound can confirm that something happened without requiring you to look at it.

This is particularly useful for interactions such as:

  • Button presses
  • Toggles and switches
  • Navigation
  • Copy actions
  • Successful operations
  • Errors
  • Menus and command palettes
  • Small state changes

The important part is that these sounds should remain subtle.

The goal isn't to turn a website into a video game. It is to make interactions feel slightly more physical.

Why Synthesized Sound?#

The traditional approach would be to ship a collection of .mp3, .wav, or .ogg files and play them when an interaction happens.

For a handful of tiny UI sounds, that can feel unnecessarily heavyweight.

Synthesizing sounds in the browser gives you:

  • No audio files to download
  • No audio assets to organize
  • Precise control over the sound
  • Very short interaction cues
  • The ability to generate variations
  • A small implementation footprint

This is where the Web Audio API becomes interesting.

Instead of saying:

"Play this file."

you can essentially say:

"Generate this sound."

An oscillator can produce a tone, a gain node can shape its volume, and frequency changes can turn a simple tone into something that feels like a click, chirp, bloom, or sweep.

Using Cuelume#

Rather than building an entire sound system from scratch, I used Cuelume.

Cuelume provides a curated collection of interaction sounds that are synthesized live using the Web Audio API. It ships without audio files and has zero runtime dependencies.

The library includes sounds for things like:

  • tick
  • press
  • release
  • toggle
  • success
  • error
  • bloom
  • chime
  • sparkle
  • pulse
  • arrival

That makes it much easier to experiment with sound without having to become an audio designer first.

The basic setup is intentionally simple:

typescript
import { bind } from "cuelume";
bind();

You can then attach sounds directly to elements:

html
<button data-cuelume-press data-cuelume-release>
Save
</button>
<a data-cuelume-hover="tick">
Docs
</a>
<button data-cuelume-toggle>
Dark mode
</button>

Or trigger a sound programmatically:

typescript
import { play } from "cuelume";
await navigator.clipboard.writeText(text);
play("success");

This is one of the things I like about the library. The component doesn't need to know anything about oscillators, frequencies, gain envelopes, or audio contexts.

It just says:

this interaction should sound like this.

Sound Should Behave Like Motion#

A useful way to think about interface audio is to treat it like animation.

You probably wouldn't animate every single element on a page.

Instead, motion is useful when it communicates something:

  • Something appeared
  • Something disappeared
  • A state changed
  • An action completed
  • The user interacted with something

Sound follows the same principle.

A few carefully chosen sounds are much better than attaching audio to every click.

For example:

InteractionSound
Button presspress
Button releaserelease
Toggletoggle
Successful actionsuccess
Recoverable errorerror
Navigationarrival
Hovertick
Revealbloom

The exact mapping isn't important.

The consistency is.

Once a user subconsciously learns that a certain sound means "something succeeded", the sound becomes another piece of the interface language.

Keep It Almost Invisible#

The best UI sounds are often the ones you barely notice.

For small interactions, I prefer sounds that are extremely short and quiet.

A few useful rules:

  1. Keep micro-interactions short.
  2. Keep the volume low.
  3. Avoid harsh high frequencies.
  4. Use smooth volume envelopes.
  5. Avoid sounds that become annoying when repeated.
  6. Never use sound as the only indication of an important state.

If you consciously notice the sound every single time you click something, it is probably too loud or too distinctive.

The ideal reaction is closer to:

"Oh, that felt responsive."

rather than:

"Why is this website making noises?"

Variation Prevents Repetition#

Another problem with UI audio is repetition.

If the exact same sound plays hundreds of times, your brain starts noticing it.

Small variations can make repeated interactions feel less robotic.

For example, instead of always generating exactly the same pitch, a sound system can vary the frequency slightly:

typescript
const frequencies = [420, 440, 460, 480];
const frequency =
frequencies[Math.floor(Math.random() * frequencies.length)];

The variation should be small.

You want the sounds to feel like the same interaction, not four completely different effects.

Libraries such as Cuelume make this experimentation easier because you can focus on choosing the right sonic character instead of implementing the underlying synthesis yourself.

Accessibility Still Comes First#

Audio should always be an enhancement.

The website should remain completely usable with sound disabled.

Cuelume provides controls for enabling/disabling playback and adjusting the global volume:

typescript
import { setEnabled, setVolume } from "cuelume";
setVolume(0.4);
setEnabled(false);

The application should own the actual user preference, so a site can expose something like:

Settings → Sound effects → On / Off

and persist that preference however it already handles user settings. Cuelume itself does not persist the preference.

It's also worth respecting accessibility preferences for motion and keeping audio non-essential. prefers-reduced-motion is not technically an audio preference, so it shouldn't automatically mean "mute everything", but it can be useful when designing a broader reduced-effects mode.

One More Browser Constraint#

Browsers generally won't allow arbitrary audio playback immediately when someone opens a page.

The user needs to interact with the page first.

This is one reason interaction-triggered sounds work particularly well. A click, key press, toggle, or other intentional action provides the browser with the user interaction needed to start audio playback.

Cuelume also handles a number of these browser concerns internally, including a shared lazy AudioContext, suspended contexts, SSR-safe imports, and graceful fallback when Web Audio isn't available.

That means the rest of the application can mostly think in terms of sound semantics, rather than browser audio plumbing.

The Interesting Part#

What I find interesting about this isn't really the sound itself.

It's the idea that a web interface doesn't have to communicate exclusively through pixels.

We already use:

  • Animation for motion
  • Haptics on mobile
  • Typography for hierarchy
  • Color for state
  • Sound for feedback

Adding a tiny amount of audio can make an interface feel considerably more responsive without making it feel noisy.

And because modern browsers already give us the Web Audio API, this doesn't necessarily require shipping a pile of audio assets.

A few lines of code can create something that makes a button feel physical.

That's a surprisingly powerful little detail.

Try It Yourself#

If you want to experiment with this, check out Cuelume. It is open source under the MIT license and available on npm.

  • Cuelume
  • Cuelume on npm
  • Cuelume on GitHub
  • Web Audio API on MDN

Start with one or two interactions.

Keep the volume low.

And if you can use your website for ten minutes without thinking about the sounds, you've probably done it right.

Sound should make an interface feel more responsive, not make the interface louder.

Vivek Patil

Vivek Patil

Crafting software, ricing Linux & building local-first tools.

All posts
·