ReactJS

React.js Mastery: Building a Global, Accessible Notification System

React.js Mastery: Building a Global, Accessible Notification System

Table of Contents

  1. Introduction
  2. The Notification Context
  3. Creating the SystemMessage Component
  4. Implementing the Banner Component
  5. Integrating Notifications Across Components
  6. Accessibility Features
  7. Conclusion

Introduction

In modern web applications, effective communication with users is crucial. A well-designed notification system can significantly enhance user experience. This article will guide you through creating a sophisticated, accessible, and globally managed single-banner notification system in React.js.

The Notification Context

Let's start by creating a powerful context to manage our global notification state:

// NotificationContext.js
import React, { createContext, useState, useContext } from 'react';

const NotificationContext = createContext();

export const NotificationProvider = ({ children }) => {
  const [notification, setNotification] = useState(null);

  const showNotification = (message, type = 'info', placeholder = 'default') => {
    setNotification({ message, type, placeholder });
  };

  const hideNotification = () => {
    setNotification(null);
  };

  return (
    <NotificationContext.Provider value={{ notification, showNotification, hideNotification }}>
      {children}
    </NotificationContext.Provider>
  );
};

export const useNotification = () => useContext(NotificationContext);

Creating the SystemMessage Component

Now, let's create the SystemMessage component that will be used in different parts of our application:

// SystemMessage.js
import React from 'react';
import { useNotification } from './NotificationContext';
import Banner from './Banner';

const SystemMessage = ({ placeholder = 'default' }) => {
  const { notification } = useNotification();

  if (!notification || notification.placeholder !== placeholder) return null;

  return <Banner {...notification} />;
};

export default SystemMessage;

Implementing the Banner Component

The Banner component will handle the actual display of our notifications:

// Banner.js
import React, { useEffect, useRef } from 'react';
import { useNotification } from './NotificationContext';

const Banner = ({ message, type }) => {
  const { hideNotification } = useNotification();
  const bannerRef = useRef(null);

  useEffect(() => {
    if (bannerRef.current) {
      bannerRef.current.focus();
    }
  }, []);

  return (
    <div
      ref={bannerRef}
      role="alert"
      aria-live="assertive"
      className={`banner banner-${type}`}
      tabIndex={-1}
    >
      <p>{message}</p>
      <button
        onClick={hideNotification}
        aria-label="Close notification"
      >
        ×
      </button>
    </div>
  );
};

export default Banner;

Integrating Notifications Across Components

Here's how to integrate the notification system into different components of your application:

// App.js
import React from 'react';
import { NotificationProvider } from './NotificationContext';
import Dashboard from './Dashboard';
import Profile from './Profile';

const App = () => {
  return (
    <NotificationProvider>
      <Dashboard />
      <Profile />
    </NotificationProvider>
  );
};

export default App;

// Dashboard.js
import React from 'react';
import { useNotification } from './NotificationContext';
import SystemMessage from './SystemMessage';

const Dashboard = () => {
  const { showNotification } = useNotification();

  const handleClick = () => {
    showNotification('Dashboard action successful!', 'success', 'dashboard');
  };

  return (
    <div>
      <SystemMessage placeholder="dashboard" />
      <h1>Dashboard</h1>
      <button onClick={handleClick}>Perform Dashboard Action</button>
    </div>
  );
};

export default Dashboard;

// Profile.js
import React from 'react';
import { useNotification } from './NotificationContext';
import SystemMessage from './SystemMessage';

const Profile = () => {
  const { showNotification } = useNotification();

  const handleClick = () => {
    showNotification('Profile updated successfully!', 'success', 'profile');
  };

  return (
    <div>
      <SystemMessage placeholder="profile" />
      <h1>User Profile</h1>
      <button onClick={handleClick}>Update Profile</button>
    </div>
  );
};

export default Profile;

Accessibility Features

Our notification system is designed with accessibility in mind:

  1. The role="alert" and aria-live="assertive" attributes ensure immediate announcement by screen readers.
  2. The banner receives focus when it appears, making it discoverable for keyboard users.
  3. The close button includes an aria-label for clear description.
  4. tabIndex={-1} allows programmatic focus without affecting the natural tab order.
  5. ScreenReaders and NVDA complient.

Conclusion

We've created a powerful, flexible, and accessible single-banner notification system for React.js applications. This system ensures that only one notification is displayed at a time, providing a clean and focused user experience.

Key features of our notification system:

  • Global state management using React Context
  • Single-banner display across the entire application
  • Contextual positioning through placeholders
  • Accessibility-compliant implementation

By integrating SystemMessage components into specific parts of your application, you can control where notifications may appear while maintaining a centralized management system. This approach offers a perfect balance between flexibility and simplicity, resulting in an effective and user-friendly notification system.

Remember to consider user experience when implementing notifications in your application. Use them judiciously to inform and guide users without overwhelming them. Happy coding!

A blog for self-taught engineers

Сommunity is filled with like-minded individuals who are passionate about learning and growing as engineers.