DEV Community

James Parker
James Parker

Posted on

Building Toast Notification Systems with react-toast in React

react-toast is a flexible and customizable library for displaying toast notifications in React applications. It provides a simple API for showing temporary messages with various types, positions, and customization options. This guide walks through setting up and creating toast notification systems using react-toast with React, from installation to a working implementation. This is part 35 of a series on using react-toast with React.

Prerequisites

Before you begin, make sure you have:

  • Node.js version 14.0 or higher installed
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) or create-react-app setup
  • Basic knowledge of React hooks (useState, useEffect, useCallback)
  • Familiarity with JavaScript/TypeScript
  • Understanding of CSS for styling

Installation

Install react-toast using your preferred package manager:

npm install react-toast
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add react-toast
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add react-toast
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "react-toast": "^1.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

Set up the toast container in your main entry file:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ToastContainer } from 'react-toast';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
    <ToastContainer />
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

First Example / Basic Usage

Let's create a simple toast notification component. Create a new file src/ToastExample.jsx:

// src/ToastExample.jsx
import React from 'react';
import { toast } from 'react-toast';

function ToastExample() {
  const showSuccessToast = () => {
    toast.success('Operation completed successfully!');
  };

  const showErrorToast = () => {
    toast.error('Something went wrong!');
  };

  const showInfoToast = () => {
    toast.info('Here is some information.');
  };

  const showWarningToast = () => {
    toast.warning('Please review your input.');
  };

  return (
    <div style={{ padding: '20px' }}>
      <h2>Toast Notification Examples</h2>
      <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
        <button onClick={showSuccessToast}>Success Toast</button>
        <button onClick={showErrorToast}>Error Toast</button>
        <button onClick={showInfoToast}>Info Toast</button>
        <button onClick={showWarningToast}>Warning Toast</button>
      </div>
    </div>
  );
}

export default ToastExample;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import ToastExample from './ToastExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <ToastExample />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This creates basic toast notifications that appear when you click the buttons and automatically disappear after a few seconds.

Understanding the Basics

react-toast provides several key features:

  • toast.success: Show a success toast
  • toast.error: Show an error toast
  • toast.info: Show an info toast
  • toast.warning: Show a warning toast
  • toast.show: Show a custom toast with options
  • ToastContainer: Component that renders all toasts
  • Positioning: Customizable toast positions
  • Customization: Extensive styling and behavior options

Key concepts:

  • Toast Container: ToastContainer must be rendered in your app to display toasts
  • Toast API: Use the toast object to show different types of toasts
  • Automatic Dismissal: Toasts automatically disappear after a set duration
  • Positioning: Toasts can be positioned in different corners
  • Customization: Toast appearance and behavior can be customized with options

Here's an example with custom options:

// src/CustomToastExample.jsx
import React from 'react';
import { toast } from 'react-toast';

function CustomToastExample() {
  const showCustomToast = () => {
    toast.show('Custom toast message', {
      type: 'success',
      duration: 5000,
      position: 'top-right'
    });
  };

  const showLongToast = () => {
    toast.success('This is a longer toast message that will stay visible for 10 seconds', {
      duration: 10000
    });
  };

  const showBottomToast = () => {
    toast.info('This toast appears at the bottom', {
      position: 'bottom-center'
    });
  };

  const showPersistentToast = () => {
    toast.warning('This toast will not auto-dismiss', {
      duration: 0
    });
  };

  return (
    <div style={{ padding: '20px' }}>
      <h2>Custom Toast Examples</h2>
      <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
        <button onClick={showCustomToast}>Custom Toast</button>
        <button onClick={showLongToast}>Long Duration Toast</button>
        <button onClick={showBottomToast}>Bottom Position Toast</button>
        <button onClick={showPersistentToast}>Persistent Toast</button>
      </div>
    </div>
  );
}

export default CustomToastExample;
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a comprehensive notification system with a custom hook and different notification patterns:

// src/hooks/useToastNotifications.js
import { useCallback } from 'react';
import { toast } from 'react-toast';

export const useToastNotifications = () => {
  const showSuccess = useCallback((message, options = {}) => {
    toast.success(message, {
      duration: 3000,
      position: 'top-right',
      ...options
    });
  }, []);

  const showError = useCallback((message, options = {}) => {
    toast.error(message, {
      duration: 5000,
      position: 'top-right',
      ...options
    });
  }, []);

  const showWarning = useCallback((message, options = {}) => {
    toast.warning(message, {
      duration: 4000,
      position: 'top-right',
      ...options
    });
  }, []);

  const showInfo = useCallback((message, options = {}) => {
    toast.info(message, {
      duration: 3000,
      position: 'top-right',
      ...options
    });
  }, []);

  const showLoading = useCallback((message) => {
    return toast.show(message, {
      type: 'info',
      duration: 0,
      position: 'top-right'
    });
  }, []);

  return {
    showSuccess,
    showError,
    showWarning,
    showInfo,
    showLoading
  };
};
Enter fullscreen mode Exit fullscreen mode

Now create an advanced notification system component:

// src/AdvancedToastSystem.jsx
import React, { useState } from 'react';
import { useToastNotifications } from './hooks/useToastNotifications';
import { toast } from 'react-toast';

function AdvancedToastSystem() {
  const { showSuccess, showError, showWarning, showInfo, showLoading } = useToastNotifications();
  const [formData, setFormData] = useState({
    message: '',
    type: 'success',
    duration: 3000
  });

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: name === 'duration' ? parseInt(value) || 0 : value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!formData.message) {
      showError('Please enter a message.');
      return;
    }

    const options = {
      duration: formData.duration || undefined,
      position: 'top-right'
    };

    switch (formData.type) {
      case 'success':
        showSuccess(formData.message, options);
        break;
      case 'error':
        showError(formData.message, options);
        break;
      case 'warning':
        showWarning(formData.message, options);
        break;
      case 'info':
        showInfo(formData.message, options);
        break;
      default:
        showInfo(formData.message, options);
    }

    setFormData({ message: '', type: 'success', duration: 3000 });
  };

  const simulateApiCall = async () => {
    const loadingId = showLoading('Processing your request...');

    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 2000));

      // Dismiss loading and show success
      toast.dismiss(loadingId);
      showSuccess('Operation completed successfully!');
    } catch (error) {
      toast.dismiss(loadingId);
      showError('Failed to complete operation. Please try again.');
    }
  };

  const showCustomStyledToast = () => {
    toast.show('Custom styled toast notification', {
      type: 'success',
      duration: 3000,
      position: 'top-center',
      style: {
        backgroundColor: '#4caf50',
        color: 'white',
        borderRadius: '8px',
        padding: '16px',
        fontSize: '16px'
      }
    });
  };

  const showActionToast = () => {
    toast.show('Item will be deleted', {
      type: 'warning',
      duration: 0,
      position: 'bottom-left',
      action: {
        label: 'Undo',
        onClick: () => {
          showSuccess('Action cancelled');
        }
      }
    });
  };

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h1>Advanced Toast System</h1>

      <form onSubmit={handleSubmit} style={{ marginBottom: '20px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Message *
          </label>
          <input
            type="text"
            name="message"
            value={formData.message}
            onChange={handleInputChange}
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box'
            }}
            required
          />
        </div>

        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Type
          </label>
          <select
            name="type"
            value={formData.type}
            onChange={handleInputChange}
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box'
            }}
          >
            <option value="success">Success</option>
            <option value="error">Error</option>
            <option value="warning">Warning</option>
            <option value="info">Info</option>
          </select>
        </div>

        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Duration (ms)
          </label>
          <input
            type="number"
            name="duration"
            value={formData.duration}
            onChange={handleInputChange}
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box'
            }}
          />
          <small style={{ color: '#666' }}>0 for persistent notification</small>
        </div>

        <button
          type="submit"
          style={{
            width: '100%',
            padding: '10px',
            backgroundColor: '#007bff',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer',
            fontSize: '16px'
          }}
        >
          Show Toast
        </button>
      </form>

      <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
        <button
          onClick={simulateApiCall}
          style={{
            padding: '10px',
            backgroundColor: '#28a745',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Simulate API Call
        </button>
        <button
          onClick={showCustomStyledToast}
          style={{
            padding: '10px',
            backgroundColor: '#ffc107',
            color: 'black',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Show Custom Styled Toast
        </button>
        <button
          onClick={showActionToast}
          style={{
            padding: '10px',
            backgroundColor: '#dc3545',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Show Action Toast
        </button>
      </div>
    </div>
  );
}

export default AdvancedToastSystem;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import { ToastContainer } from 'react-toast';
import AdvancedToastSystem from './AdvancedToastSystem';
import './App.css';

function App() {
  return (
    <div className="App">
      <AdvancedToastSystem />
      <ToastContainer position="top-right" />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Common Issues / Troubleshooting

  1. Toasts not displaying: Ensure ToastContainer is rendered in your app. It should be placed at the root level, typically in your main App component.

  2. Toasts appearing in wrong position: Use the position option when calling toast functions or set it on the ToastContainer component. Available positions include 'top-left', 'top-right', 'top-center', 'bottom-left', 'bottom-right', 'bottom-center'.

  3. Toasts not auto-dismissing: Check the duration option. Set a duration in milliseconds (e.g., 3000 for 3 seconds). If duration is 0, toasts will not auto-dismiss.

  4. Multiple toast containers: You can have multiple ToastContainer components with different positions to show toasts in different locations simultaneously.

  5. Custom styling not working: Use the style option when calling toast functions to apply custom styles. Make sure styles are valid CSS properties.

  6. Action buttons not working: When using the action option, ensure the onClick handler is properly defined. Action toasts typically have duration: 0 to prevent auto-dismissal.

Next Steps

Now that you have an understanding of react-toast:

  • Explore advanced customization options
  • Learn about different toast positions and animations
  • Implement toast queues and limits
  • Add custom toast components
  • Integrate with React Context for global toast management
  • Learn about other toast libraries (react-toastify, notistack)
  • Check the official repository: https://github.com/moharnadreza/react-toast
  • Look for part 36 of this series for more advanced topics

Summary

You've successfully set up react-toast in your React application and created a toast notification system with custom hooks and different notification patterns. react-toast provides a flexible API for displaying temporary messages with extensive customization options.

SEO Keywords

react-toast
React toast notifications
react-toast tutorial
React notification library
react-toast installation
React toast messages
react-toast example
React alert notifications
react-toast setup
React toast hooks
react-toast customization
React notification system
react-toast container
React toast library
react-toast getting started

Top comments (0)