Special Sale - Up to23%Off!Shop Now
Blog

2024-12-09ยทnext.jsreact

How to Add Sound Effects to Toast Notifications in Next.js 14 & 15 | Complete Guide

Taher Hathi

Taher Hathi avatar

Taher Hathi

Learn how to add audio feedback to Next.js toast notifications using react-hot-toast and Web Audio API. Step-by-step tutorial with code examples for success, error, and custom sounds.

Cover image

How to Add Sound Effects to Toast Notifications in Next.js

Toast notifications are essential UI components for providing user feedback, but adding audio cues can significantly improve user experience and accessibility. In this comprehensive tutorial, you'll learn how to implement toast notifications with sound effects in Next.js 14 and 15 using react-hot-toast and the Web Audio API.

Why Add Sound to Toast Notifications?

Audio feedback in toast notifications provides multiple benefits for modern web applications:

Improved Accessibility: Sound notifications help visually impaired users and those using screen readers understand when actions are completed.

Better User Experience: Audio cues create a more responsive, polished application feel that increases user confidence.

Increased Attention: Sound ensures users notice important notifications even when multitasking or looking away from the screen.

Enhanced Feedback Loop: Combining visual and auditory feedback reinforces successful or failed actions, reducing user confusion.

Prerequisites

Before starting this tutorial, ensure you have:

  • Next.js 14 or 15 installed (App Router)
  • Basic understanding of React hooks and TypeScript
  • Node.js 18+ and npm or yarn installed
  • A Next.js project set up and running

Installing Dependencies

First, install the react-hot-toast library for toast notifications:

1npm install react-hot-toast
2# or
3yarn add react-hot-toast
4# or
5pnpm add react-hot-toast

React-hot-toast is a lightweight, customizable toast notification library that works seamlessly with Next.js and provides excellent TypeScript support.

Creating the ToastSound Component

Create a new file at components/ToastSound.tsx. This component will handle audio playback using the Web Audio API:

1"use client";
2
3import { useEffect, useRef } from "react";
4import { useToasterStore } from "react-hot-toast";
5
6// Plays a synthesized chime sound based on notification type
7// kind - The type of notification: 'success', 'error', or default
8function playChime(kind: string) {
9  try {
10    // Initialize Web Audio API context

Understanding the Code

Web Audio API: The playChime function uses the Web Audio API to generate tones programmatically without external audio files, reducing bundle size and load times.

Frequency Mapping: Different notification types use distinct frequencies for instant recognition:

  • Error notifications: 320 Hz (lower, urgent tone)
  • Success notifications: 660 Hz (higher, pleasant tone)
  • Default notifications: 520 Hz (neutral middle tone)

Performance Optimization: The playedRef Set tracks played toasts, preventing duplicate sounds on re-renders.

Progressive Enhancement: Both audio and vibration functions use try-catch blocks for graceful degradation in unsupported browsers.

Setting Up the Toast Provider

Create a provider component at components/ToastProvider.tsx:

1"use client";
2
3import { Toaster } from "react-hot-toast";
4import ToastSound from "./ToastSound";
5
6// ToastProvider - Wraps the application with toast notification functionality
7// Includes both visual toasts and audio feedback
8export default function ToastProvider() {
9  return (
10    <>

Implementing in Your Next.js App

Step 1: Add Provider to Root Layout

In your app/layout.tsx, include the ToastProvider:

1import type { Metadata } from "next";
2import ToastProvider from "@/components/ToastProvider";
3import "./globals.css";
4
5export const metadata: Metadata = {
6  title: "My Next.js App with Toast Sounds",
7  description: "Next.js application with audio-enabled toast notifications",
8};
9
10export default function RootLayout({

Step 2: Use Toasts in Components

Create toast notifications anywhere in your application:

1"use client";
2
3import toast from "react-hot-toast";
4import { useState } from "react";
5
6export default function ToastDemo() {
7  const [loading, setLoading] = useState(false);
8
9  const handleSuccess = () => {
10    toast.success("Operation completed successfully!");

Customization Options

Custom Sound Frequencies

Adjust frequencies to match your brand identity:

1// Softer, more subtle tones
2const freq = kind === "error" ? 280 : kind === "success" ? 720 : 480;
3
4// More pronounced differences
5const freq = kind === "error" ? 240 : kind === "success" ? 880 : 520;

Volume Control

Modify the gain envelope for louder or quieter sounds:

1// Louder sound
2g.gain.exponentialRampToValueAtTime(0.12, now + 0.02);
3
4// Quieter sound
5g.gain.exponentialRampToValueAtTime(0.05, now + 0.02);

Sound Duration

Change the duration by adjusting the stop time:

1// Longer sound (300ms)
2o.stop(now + 0.3);
3
4// Shorter sound (100ms)
5o.stop(now + 0.1);

Using Custom Audio Files

For more complex sounds, replace synthesized tones with audio files:

1function playAudioFile(kind: string) {
2  try {
3    const audio = new Audio(`/sounds/${kind}.mp3`);
4    audio.volume = 0.5;
5    audio.play().catch((error) => {
6      console.warn('Audio playback failed:', error);
7    });
8  } catch (error) {
9    console.warn('Audio not supported');
10  }

Place audio files in your public/sounds/ directory:

  • public/sounds/success.mp3
  • public/sounds/error.mp3
  • public/sounds/blank.mp3

Adding User Preferences

Allow users to control sound settings:

1"use client";
2
3import { create } from 'zustand';
4import { persist } from 'zustand/middleware';
5
6interface SoundPreferences {
7  enabled: boolean;
8  volume: number;
9  toggleSound: () => void;
10  setVolume: (volume: number) => void;

Accessibility Best Practices

When implementing audio notifications, follow these accessibility guidelines:

1. Provide Sound Controls

Always give users the ability to disable sounds:

1export default function SoundControls() {
2  const { enabled, toggleSound } = useSoundPreferences();
3  
4  return (
5    <button
6      onClick={toggleSound}
7      aria-label={enabled ? "Mute notifications" : "Unmute notifications"}
8      className="flex items-center gap-2"
9    >
10      {enabled ? "๐Ÿ”Š Sound On" : "๐Ÿ”‡ Sound Off"}

2. Respect System Preferences

Check for user's reduced motion preferences:

1const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
2
3if (prefersReducedMotion) {
4  // Disable or reduce audio feedback
5  return;
6}

3. Keep Sounds Brief

Limit sound duration to 200-300ms to avoid annoyance and maintain a professional feel.

4. Don't Rely Solely on Audio

Always provide visual feedback alongside audio cues. Never use sound as the only notification method.

5. ARIA Attributes

Ensure toast notifications have proper ARIA attributes:

1<Toaster
2  position="top-right"
3  toastOptions={{
4    ariaProps: {
5      role: 'status',
6      'aria-live': 'polite',
7    },
8  }}
9/>

Browser Compatibility

The Web Audio API is supported in all modern browsers:

  • Chrome: 34+ โœ…
  • Firefox: 25+ โœ…
  • Safari: 14.1+ โœ…
  • Edge: 79+ โœ…
  • Opera: 21+ โœ…
  • Mobile browsers: iOS Safari 14.5+, Chrome Android 91+ โœ…

The Vibration API has more limited support:

  • Supported: Chrome, Firefox, Edge (mobile)
  • Not supported: Safari, iOS devices

Our implementation includes fallback handling, so unsupported browsers simply won't play audio without breaking functionality.

Common Issues and Solutions

Issue 1: Sound Not Playing

Problem: Toast appears but no sound plays.

Solutions:

  1. Check browser autoplay policies - some browsers require user interaction first
  2. Verify Web Audio API support in browser console
  3. Check if sound is muted in browser or system settings
1// Test Web Audio API support
2const isSupported = 'AudioContext' in window || 'webkitAudioContext' in window;
3console.log('Web Audio API supported:', isSupported);

Issue 2: Multiple Sounds Playing

Problem: Same toast triggers sound multiple times.

Solution: Ensure playedRef is properly tracking toast IDs (already implemented in our code).

Issue 3: Sound Delay

Problem: Noticeable delay between toast appearance and sound.

Solution: Pre-initialize AudioContext on user interaction:

1let audioContext: AudioContext | null = null;
2
3export function initAudioContext() {
4  if (!audioContext) {
5    const AudioCtx = window.AudioContext || (window as any).webkitAudioContext;
6    audioContext = new AudioCtx();
7  }
8  return audioContext;
9}

Issue 4: Hydration Errors

Problem: Next.js hydration mismatch errors.

Solution: Ensure components are marked with "use client" directive and avoid accessing window during SSR.

Performance Optimization Tips

1. Lazy Load Audio Context

Initialize the AudioContext only when needed to reduce initial bundle size.

2. Debounce Rapid Toasts

Prevent sound overlap for rapidly triggered toasts:

1let lastSoundTime = 0;
2const SOUND_DEBOUNCE = 300; // ms
3
4function playChime(kind: string) {
5  const now = Date.now();
6  if (now - lastSoundTime < SOUND_DEBOUNCE) return;
7  lastSoundTime = now;
8  
9  // ... rest of playChime code
10}

3. Clean Up Resources

Properly dispose of AudioContext when component unmounts:

1useEffect(() => {
2  return () => {
3    // Cleanup
4    playedRef.current.clear();
5  };
6}, []);

Advanced Features

Custom Toast Types with Unique Sounds

Create custom toast types for specific use cases:

1// Custom warning toast
2toast.custom((t) => (
3  <div className="bg-yellow-500 text-white p-4 rounded">
4    โš ๏ธ {t.message}
5  </div>
6), { type: 'warning' });
7
8// Update playChime to handle warning type
9const freq = 
10  kind === "error" ? 320 : 

Integration with Form Validation

Combine with form libraries like React Hook Form:

1import { useForm } from "react-hook-form";
2import toast from "react-hot-toast";
3
4export default function MyForm() {
5  const { register, handleSubmit, formState: { errors } } = useForm();
6
7  const onSubmit = async (data: any) => {
8    try {
9      await submitForm(data);
10      toast.success("Form submitted successfully!");

Conclusion

Adding sound effects to toast notifications in Next.js enhances user experience through multi-sensory feedback. By following this tutorial, you've learned how to:

  • Implement the Web Audio API for synthesized sounds
  • Integrate react-hot-toast with Next.js 14/15 App Router
  • Create accessible, customizable audio notifications
  • Handle browser compatibility and edge cases
  • Optimize performance and user preferences

The combination of visual, audio, and haptic feedback creates a polished, professional application that users will appreciate.

Frequently Asked Questions

Q: Can I use this with Next.js Pages Router?

A: Yes, simply remove the "use client" directive and import the provider in _app.tsx.

Q: Does this work with React Native?

A: No, this tutorial is for web applications. React Native requires different audio APIs.

Q: How do I add different sounds for each notification?

A: Modify the playChime function's frequency mapping or use separate audio files.

Q: Will this increase my bundle size?

A: Minimally - the Web Audio API is native to browsers, and the code adds less than 2KB.

Q: Can I use this in production?

A: Yes, the Web Audio API is stable and widely supported across modern browsers.


Last Updated: December 2024
Compatible with: Next.js 14+, React 18+, react-hot-toast 2.4+

Share this post

How to Add Sound Effects to Toast Notifications in Next.js 14 & 15 | Complete Guide | Nextjsshop Blog