2024-12-09ยทnext.jsreact
How to Add Sound Effects to Toast Notifications in Next.js 14 & 15 | Complete Guide
Taher Hathi
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.

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-toastReact-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 contextUnderstanding 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.mp3public/sounds/error.mp3public/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:
- Check browser autoplay policies - some browsers require user interaction first
- Verify Web Audio API support in browser console
- 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.
Related Resources
- Next.js Documentation - Official Next.js guides
- react-hot-toast Documentation - Complete API reference
- Web Audio API MDN - In-depth Web Audio guide
- Accessibility Guidelines - WCAG standards
- TypeScript Handbook - TypeScript best practices
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+