# How to Implement React Notifications — Including...

> Learn how to implement effective notifications in React applications. Explore the differences between stateless and stateful notifications, and...

Canonical: https://novu.co/blog/react-notifications/

Markdown: https://novu.co/blog/react-notifications.md

Last updated: 2024-07-19T14:04:00.000Z

Learn how to implement effective notifications in React applications. Explore the differences between stateless and stateful notifications, and discover the best libraries and practices for enhancing user engagement and information delivery in your…

Authors: Emil Pearce

Published: 2024-07-19T14:04:00.000Z

Category: How to

Table of contents

- [Introduction to React notifications](<#ad5d1db2-3190-409a-a785-994f8f7b6700>)

  - [What are notifications?](<#667d1d67-41d6-410e-be31-199d990182e0>)

    - [Important considerations](<#c28e4692-d624-418f-8a78-c883d59e83a1>)

  - [Types of notifications in React](<#8df719d0-5c0a-4794-83ed-a1a058beb220>)

    - [Stateless notifications](<#3db015e2-f75d-4a30-8667-20c9752d3746>)

    - [Stateful notifications](<#f0773085-3bab-4cb2-be9b-513e3df68c95>)

    - [Notification type comparison](<#5c7b4394-5f86-4eac-af9e-1d1138b738bc>)

  - [Setting up React stateless notifications](<#a019073a-4cf5-4b4e-ae4f-8a7217e41f09>)

    - [Pop-up notifications](<#95ea17a1-195a-40b8-ae94-0e5cfe9b5311>)

    - [Modal notifications](<#19a29526-382d-4590-a9a9-f8a176970602>)

  - [Open source stateless notifications solutions](<#4e7ed69a-29c3-4c91-8ce1-30252e10d746>)

    - **[react-toastify](<#e0c25989-c8c7-4760-8277-8a0bdd1f8bdf>)**

    - **[react-hot-toast](<#d8a065b4-4676-4a5f-8ad3-ee5fcb0ab849>)**

    - **[notistack](<#bed77970-f00d-44d8-914d-684a31bfa422>)**

    - **[react-notification-system](<#1be4c8dc-fb91-43aa-a64d-662a48624d3d>)**

    - **[react-toast-notifications](<#8de64dfe-45c8-44e4-820a-128c948394a1>)**

    - **[reapop](<#d53a0c3a-8774-4deb-b4ab-4dd61a2c31cd>)**

    - **[react-notifications-component](<#59e5bddc-f44f-4014-9831-4a9e0533f30b>)**

    - **[react-redux-toastr](<#0a2cdc01-e3ec-4a51-80e4-91a017125968>)**

    - **[notiflix](<#51fad301-45a9-4d8c-82c3-1fb7be6a7d1e>)**

    - **[react-modal](<#d8a697df-497e-47c7-829b-ba5bb85964b2>)**

    - react-aria

  - [Recommendations for stateless notifications](<#364c3c26-e000-4d73-b501-ca66d2613fda>)

  - [Stateless notifications implementation](<#cb217743-6f12-4615-b551-d0633f89478e>)

    - **[Requirements](<#38825390-f777-44de-ab9c-9a87c4f14c4e>)**

    - **[Installation](<#046bb31d-f9e9-4f33-935c-e742f373062a>)**

    - **[The gist](<#217844ed-b006-4e2b-91c9-fcbde3ba6dc3>)**

    - [Best practices](<#f28e2e6a-182f-4169-a7f8-70b6c38be3d4>)

    - [Customization](<#45feadd5-1ee7-42cf-b956-4f22af398c8c>)

    - [Testing](<#bdac9ea5-1d35-4d1a-9fb1-f1a052232727>)

  - [Setting Up React stateful notifications](<#64973d58-3cd6-4f7f-8a5c-91f876d4b8d6>)

    - [In-App notifications](<#cd362583-e060-4144-8f8d-49a309660ce9>)

  - [Open source notification solutions](<#ae645d70-0382-4c32-9b0f-cf3a829b928b>)

    - [Novu](<#d2041515-16d4-46ea-b81b-52d667e40c00>)

  - [Recommendations for stateful notifications](<#c53a2e95-72d1-4fe1-9f13-8e630b4d84b9>)

  - [Stateful notifications implementation](<#37887bf5-1c59-4562-b194-0ee0d5610327>)

    - **[Requirements](<#63084950-5b1a-489c-a309-7d06c8a265dc>)**

    - **[Installation](<#09289f85-d01f-4645-9ade-a9e66cc1dbf6>)**

    - **[The gist](<#c34b3a38-1277-4942-bfcd-8003b8035a2d>)**

    - [Best practices](<#4cad7490-95cd-4df3-9e71-00536ce4685f>)

    - [Customization](<#c7942d6e-5dd3-4b40-9d0a-699dd32ad02f>)

    - [Testing](<#85482483-d4b4-43dd-8c78-6626528c05bb>)

## Introduction to React notifications

Notifications in React applications are essential for user engagement and information delivery, and they can vary significantly in complexity and functionality.

## What are notifications?

Simple notifications, such as **alerts**, **pop-ups**, or **toasts**, provide immediate, transient messages that require minimal user interaction and are typically used for quick updates or warnings. **Modals** or **dialog boxes**, in contrast, are more intrusive and often require user action before proceeding, making them suitable for tasks like form submissions or confirmations. These can also be referred to as **STATELESS** notifications.

More sophisticated notification systems, like **in-app notifications**, **notification feeds**, or **inboxes**, offer a richer, context-aware experience by maintaining user interaction history and delivering tailored updates. These advanced systems can also be referred to as **STATEFUL** notifications, dynamic alerts, or personalized messages. Implementing these notifications in React can range from using libraries like [`react-toastify`](<https://www.npmjs.com/package/react-toastify>) for simple, ephemeral alerts to using libraries like [`novu`](<https://www.npmjs.com/package/novu>) for comprehensive, contextual notification feeds that enhance user engagement and ensure timely delivery of important information.

## Important considerations

When adding stateful or stateless notifications, it is crucial to remember that stateless notifications are usually a frontend user experience component, whereas stateful messages and notifications rely on backend and database connectivity. This distinction is vital for determining the architecture and dependencies of your notification system.

Understanding the distinctions between these notification types helps in designing an effective communication strategy within your application.

## Types of notifications in React

Notifications can be categorized as stateful or stateless in React software development, particularly in the context of web and mobile applications.

Here’s an explanation of both concepts:

## Stateless notifications

Stateless notifications do not keep track of any previous states or sessions. Each notification is independent, and the system sending these notifications does not maintain any information about the user’s interaction with previous notifications.

- **Characteristics**

  - **Independence:** Each notification is sent without regard to any prior notifications.

  - **Simplicity:** Easier to implement since no state or history needs to be tracked.

  - **Use Cases:** Suitable for alerts that don’t require context, such as one-time announcements, promotional messages, or simple reminders.

**(The GIF is by **[**React-Toastify**](<https://www.npmjs.com/package/react-toastify>)**)**

## Stateful notifications

Stateful notifications, on the other hand, keep track of the state or history of notifications. The system maintains information about previous interactions, allowing it to send notifications based on past user behavior or states.

- **Characteristics**

  - **Context-aware:** Notifications are tailored based on the user’s interaction history or specific states.

  - **Complexity:** More complex to implement due to the need to maintain and update user state information.

  - **Use Cases:** Ideal for notifications that require context, such as progress updates, reminders about incomplete tasks, or notifications about ongoing events.

(Image by [Jordan Hughes](<https://dribbble.com/shots/24074438-Notifications-Untitled-UI>))

## Notification type comparison

|  | Stateless notifications | Stateful notifications |
| --- | --- | --- |
| Independence | Each notification is independent | Notifications are context-aware and related |
| Complexity | Simpler to implement | More complex due to state tracking |
| Context | No user-specific context | Context-aware, tailored based on user history |
| Use cases | One-time alerts, general announcements | Progress updates, task reminders |
| Implementation | No need to maintain a user interaction history | Requires maintaining and updating user states |

## Setting up React stateless notifications

There are two common types of stateless notifications:

## Pop-up notifications

**Pop-up** notifications (or **toast notifications**, **snackbars**, **alerts**) are non-intrusive graphical elements that communicate events to the user without requiring immediate action. They usually disappear automatically after a short time but can be stored in a widget for later access.

**Here are some visual examples:**

## Modal notifications

**Modal** notifications, often referred to as **dialog boxes**, **dialogs**, **popup windows**, **popups**, **lightboxes**, **alert dialogs**, **confirmation dialogs**, **overlays**, **message boxes**, **prompts**, **modal windows**, or **inline dialogs**, are interfaces that temporarily interrupt the user’s workflow to focus on specific information or actions.

These terms highlight different aspects of modals, such as requiring user input, confirming actions, or displaying important messages, and are used interchangeably depending on the design language or framework.

**Visual modal notification examples**

(Image from [Bootstrap’s Documentation](<https://getbootstrap.com/docs/4.0/components/modal/>))

([Image Source](<https://www.newyorker.com/>))

## Open source stateless notifications solutions

These libraries enable the display of temporary messages, alerts, and other notifications in a way that is efficient, customizable, and easy to integrate into existing projects. Stateless notifications are particularly advantageous because they simplify the development process, reduce server load, and enhance the user experience by offering real-time feedback directly in the browser. Here are some of the most popular and feature-rich React libraries available for implementing such notifications, ensuring developers have access to a range of options suited to various needs and preferences.

## react-toastify (GitHub) (Demo)

**react-toastify** enables you to add notifications to your app with ease. It’s highly customizable and offers a variety of features including toast notification styles, animation options, and automatic dismissal.

- **GitHub stars:** 12.4k

- **Features**

  - Easy to set up

  - Easy to customize

  - RTL support

  - Swipe to close

  - Customize the swipe direction

  - Use an animation of your choice. (Works well with animate.css)

  - Can display a React component inside the toast

  - Has `onOpen` and `onClose` hooks (Both can access the props passed to the React component rendered inside the toast)

  - Can remove a toast programmatically

  - Define behavior per toast

  - Pause toast when the window loses focus

  - Progress bar to display the remaining time

  - Possibility to update a toast

  - Control over the progress bar

  - Limit the number of toasts displayed at the same time

  - Dark mode

  - Pause timer programmatically

  - Stacked notifications

  - And more

## react-hot-toast (GitHub) (Demo)

**react-hot-toast** is an attractive library that lets you create notifications with beautiful designs and animations.

- **GitHub stars:** 9.5k

- **Features**

  - Customizable

  - Promise API – Automatic loader from a promise

  - Lightweight – less than 5kb including styles

  - Accessible

  - Headless hooks – Create your own with [`useToaster()`](<https://react-hot-toast.com/docs/use-toaster>)

## notistack (GitHub) (Demo)

**notistack** is a library that makes it easy to display snackbar notifications. It’s built on top of Material-UI and offers various customization and configuration options.

- **GitHub stars:** 3.8k

- **Features**

  - Supports snackbar notifications

  - Can render toasts outside of the React tree

  - Supports custom toast renderers

  - Can enqueue and dismiss notifications programmatically

  - Offers rich customization options for positioning, styling, and behavior

## react-notification-system (GitHub) (Demo)

**react-notification-system** is a complete and totally customizable component for notifications in React.

- **GitHub stars:** 2.4k

- **Features**

  - Supports custom toast animations

  - Can render toasts inside modals

  - Supports custom toast renderers

  - Easily integrates with existing React components

  - Provides a robust API for controlling notifications programmatically

## react-toast-notifications (GitHub) (Demo)

A configurable, composable, toast notification system for React.

- **GitHub stars:** 2.2k

- **Features**

  - Supports custom toast themes

  - Can render toasts inside custom elements

  - Supports custom toast renderers

  - Provides a flexible and composable API for building notification systems

  - Offers fine-grained control over toast placement, appearance, and behavior

## reapop (GitHub) (Demo)

A simple and customizable React notification system

- **GitHub stars:** 1.5k

- **Features**

  - Supports multiple notification types (e.g., toasts, snackbars, alerts)

  - Can render notifications inside custom elements

  - Supports custom notification renderers

  - Provides a simple API for creating, updating, and removing notifications

  - Offers flexible configuration options for styling and behavior

## react-notifications-component (GitHub) (Demo)

This library boasts a highly configurable notification component that supports various notification types, animations, and positions.

- **GitHub stars:** 1.3k

- **Features**

  - Touch support

  - Responsive notifications

  - Standard notification types

  - Custom notification types

  - Custom notification content

  - Dismissible (touch, click, timeout)

  - Customizable transitions

  - Small library footprint

  - Provides a wide range of options for notification placement and styling

## react-redux-toastr (GitHub) (Demo)

react-redux-toastr is a toastr message generator for React and Redux, allowing for smooth integration with Redux applications.

- **GitHub stars:** 750

- **Features**

  - Provides integration with Redux

  - Can display toasts based on Redux actions

  - Can display toasts with custom Redux state

  - Supports complex workflows and state management through Redux

  - Offers a powerful API for controlling toasts within a Redux ecosystem

## notiflix (GitHub) (Demo)

notiflix is a pure JavaScript library for client-side non-blocking notifications, popup boxes, loading indicators, and more that makes your web projects much better.

- **GitHub stars:** 620

- **Features**

  - Provides a comprehensive notification library with support for toasts, snackbars, alerts, modals, and more

  - Supports multiple themes and customization options

  - Provides a variety of pre-built notification animations

  - Lightweight and easy to integrate into existing projects

  - Offers a robust API for controlling notifications programmatically

## react-modal (GitHub) (Demo)

**react-modal** is an official accessible modal dialog component for React.

- **GitHub stars:** 7.3k

- **Features**

  - Provides a comprehensive notification library with support for toasts, snackbars, alerts, modals, and more

  - Supports multiple themes and customization options

  - Provides a variety of pre-built notification animations

  - Fully accessible and compliant with WAI-ARIA guidelines

  - Highly customizable and easy to use within React applications

## react-aria (GitHub)

**react-aria** is part of [react-spectrum](<https://github.com/adobe/react-spectrum>), a collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.

- **GitHub stars:** 12.3k

- **Features**

  - Accessibility and behavior is implemented according to WAI-ARIA authoring practices

  - All components are designed to work with mouse, touch, and keyboard interactions. Built with responsive design principles

  - Support for over 30 languages included out of the box

  - Supports custom themes and automatically adapt for dark mode

## Recommendations for stateless notifications

We could recommend the **react-toastify** library**. **It is the most popular library for displaying toast messages in React applications. It provides a simple and flexible API for creating customizable toast messages, including success, error, warning, and info types.

The library allows you to set the duration, position, and styling of the toasts.

It’s highly recommended for its ease of use, extensive customization options, and advanced features. Its intuitive API and comprehensive documentation make integration straightforward.

You can tailor the appearance and behavior of toasts to match your application’s design, with options for custom animations, RTL support, swipe-to-close functionality, and more.

The library supports programmatic control over toasts, including pausing, updating, and removing them. It is actively maintained by the developer community and compatible with the latest React versions. **React Toastify**’s popularity is reflected in its large number of GitHub stars, indicating widespread use and community support.

## Stateless notifications implementation

## Requirements

[React](<https://reactjs.org/>) version &gt;= 16.8 or above

## Installation

With npm:

```bash
npm install --save react-toastify
```

With yarn:

```bash
yarn add react-toastify
```

## The gist

```javascript
import React from 'react';
  import { ToastContainer, toast } from 'react-toastify';

  import 'react-toastify/dist/ReactToastify.css';
  // minified version is also included
  // import 'react-toastify/dist/ReactToastify.min.css';

  function App(){
    const notify = () => toast("Wow so easy !");

    return (

        Notify !</button>

      </div>
    );
  }
```

**Note**: Remember to render the `ToastContainer`_once_ in your application tree.If you can’t figure out where to put it, rendering it in the application root would be the best bet.

## Best practices

**Consistent usage**

- **Uniform toast placement:** Ensure all toast notifications appear in a consistent position across your application (e.g., top-right, bottom-center). This helps users know where to look for important messages.

- **Duration management:** Set appropriate durations for different types of notifications. For instance, error messages might need more time to be read and understood compared to success messages.

- **Styling Consistency:** Maintain consistent styling for all toast notifications to align with your application’s design language. This includes colors, fonts, and animations.

**User experience**

- **Non-intrusive notifications:** Keep notifications non-intrusive. Avoid blocking the main content or important user interactions. The toast messages should be informative but not disruptive.

- **Clear messaging:** Ensure the content of the notifications is clear and concise. Users should understand the message without confusion.

- **Accessibility:** Make sure that toast notifications are accessible. Use ARIA roles and properties to ensure screen readers can announce the toast messages.

## Customization

**Override CSS variables**

Below the list of the CSS variables that are exposed by the library. You can accomplish a lot by overriding some of them.

```javascript
:root {
  --toastify-color-light: #fff;
  --toastify-color-dark: #121212;
  --toastify-color-info: #3498db;
  --toastify-color-success: #07bc0c;
  --toastify-color-warning: #f1c40f;
  --toastify-color-error: #e74c3c;
  --toastify-color-transparent: rgba(255, 255, 255, 0.7);

  --toastify-icon-color-info: var(--toastify-color-info);
  --toastify-icon-color-success: var(--toastify-color-success);
  --toastify-icon-color-warning: var(--toastify-color-warning);
  --toastify-icon-color-error: var(--toastify-color-error);

  --toastify-toast-width: 320px;
  --toastify-toast-background: #fff;
  --toastify-toast-min-height: 64px;
  --toastify-toast-max-height: 800px;
  --toastify-font-family: sans-serif;
  --toastify-z-index: 9999;

  --toastify-text-color-light: #757575;
  --toastify-text-color-dark: #fff;

  //Used only for colored theme
  --toastify-text-color-info: #fff;
  --toastify-text-color-success: #fff;
  --toastify-text-color-warning: #fff;
  --toastify-text-color-error: #fff;

  --toastify-spinner-color: #616161;
  --toastify-spinner-color-empty-area: #e0e0e0;

  // Used when no type is provided
  // toast("**hello**")
  --toastify-color-progress-light: linear-gradient(
    to right,
    #4cd964,
    #5ac8fa,
    #007aff,
    #34aadc,
    #5856d6,
    #ff2d55
  );
  // Used when no type is provided
  --toastify-color-progress-dark: #bb86fc;
  --toastify-color-progress-info: var(--toastify-color-info);
  --toastify-color-progress-success: var(--toastify-color-success);
  --toastify-color-progress-warning: var(--toastify-color-warning);
  --toastify-color-progress-error: var(--toastify-color-error);

  // used to control the opacity of the progress trail
  --toastify-color-progress-bgo: .2;
}
```

**Override existing CSS classes**

If overriding the CSS variables is not enough for you, you can override the existing CSS classes. Below, a list of the CSS classes used (classes used for animation and media query are omitted)

```javascript
/** Used to define container behavior: width, position: fixed etc... **/
.Toastify__toast-container {
}

/** Used to define the position of the ToastContainer **/
.Toastify__toast-container--top-left {
}
.Toastify__toast-container--top-center {
}
.Toastify__toast-container--top-right {
}
.Toastify__toast-container--bottom-left {
}
.Toastify__toast-container--bottom-center {
}
.Toastify__toast-container--bottom-right {
}

/** Classes for the displayed toast **/
.Toastify__toast {
}
.Toastify__toast--rtl {
}
.Toastify__toast-body {
}

/** Used to position the icon **/
.Toastify__toast-icon {
}

/** handle the notification color and the text color based on the theme **/
.Toastify__toast-theme--dark {
}
.Toastify__toast-theme--light {
}
.Toastify__toast-theme--colored.Toastify__toast--default {
}
.Toastify__toast-theme--colored.Toastify__toast--info {
}
.Toastify__toast-theme--colored.Toastify__toast--success {
}
.Toastify__toast-theme--colored.Toastify__toast--warning {
}
.Toastify__toast-theme--colored.Toastify__toast--error {
}

.Toastify__progress-bar {
}
.Toastify__progress-bar--rtl {
}
.Toastify__progress-bar-theme--light {
}
.Toastify__progress-bar-theme--dark {
}
.Toastify__progress-bar--info {
}
.Toastify__progress-bar--success {
}
.Toastify__progress-bar--warning {
}
.Toastify__progress-bar--error {
}
/** colored notifications share the same progress bar color **/
.Toastify__progress-bar-theme--colored.Toastify__progress-bar--info,
.Toastify__progress-bar-theme--colored.Toastify__progress-bar--success,
.Toastify__progress-bar-theme--colored.Toastify__progress-bar--warning,
.Toastify__progress-bar-theme--colored.Toastify__progress-bar--error {
}

/** Classes for the close button. Better use your own closeButton **/
.Toastify__close-button {
}
.Toastify__close-button--default {
}
.Toastify__close-button > svg {
}
.Toastify__close-button:hover,
.Toastify__close-button:focus {
}
```

Here you can learn more about [how to style your stateless notifications.](<https://fkhadra.github.io/react-toastify/how-to-style>)

## Testing

Testing toast notifications in a React application using `react-toastify` involves checking that the toasts appear correctly and contain the expected content. You can achieve this using testing libraries such as `Jest` and `React Testing Library`.

Keep reading for a step-by-step guide on how to include testing for `react-toastify.`

- **Setting up testing environment**

  - Ensure you have the necessary testing libraries installed:

```javascript
npm install --save-dev @testing-library/react @testing-library/jest-dom jest
```

Here’s an example test file:

- Writing tests for toast notifications

  - **Render the component with toasts**: Make sure the component that triggers the toast notifications is rendered in the test.

  - **Trigger toasts**: Simulate the actions that would cause the toast notifications to appear.

  - **Assert toasts**: Verify that the toasts appear with the correct content and attributes.

```javascript
// App.test.jsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import App from './App';  // Import your component
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

test('displays toast notification on button click', () => {
  render(
    <>

    </>
  );

  // Simulate button click to trigger the toast
  fireEvent.click(screen.getByText('Notify !'));

  // Assert the toast notification appears
  expect(screen.getByText('Wow so easy !')).toBeInTheDocument();
});

test('toast notification disappears after duration', async () => {
  render(
    <>

    </>
  );

  // Simulate button click to trigger the toast
  fireEvent.click(screen.getByText('Notify !'));

  // Assert the toast notification appears
  expect(screen.getByText('Wow so easy !')).toBeInTheDocument();

  // Wait for the toast to disappear (assuming the default duration is 5000ms)
  await new Promise((r) => setTimeout(r, 5000));

  // Assert the toast notification is removed
  expect(screen.queryByText('Wow so easy !')).not.toBeInTheDocument();
});
```

**Explanation**

1. **Setup the test environment**: The `render` function from `@testing-library/react` is used to render the `App` component along with the `ToastContainer`.

1. **Trigger the toast**: The `fireEvent.click` function simulates a button click to trigger the toast notification.

1. **Assertions**

  - `expect(screen.getByText('Wow so easy !')).toBeInTheDocument();` checks that the toast notification with the specified text appears in the document.

  - `await new Promise((r) =&gt; setTimeout(r, 5000));` introduces a delay to wait for the toast to disappear.

  - `expect(screen.queryByText('Wow so easy !')).not.toBeInTheDocument();` verifies that the toast notification is no longer in the document after the duration.

**Additional tests**

You can add more tests to cover different scenarios, such as:

- **Different Toast Types**: Test success, error, warning, and info toasts.

- **Custom Duration**: Test toasts with custom durations.

- **Positioning**: Verify that toasts appear in the correct position.

**Integration with CI/CD**

Ensure that your tests are integrated with your CI/CD pipeline to automatically run these tests on every push or pull request. This helps catch any issues early and maintains the reliability of your notifications

In case you would like to get even more into how to customize and have a better understanding overall, consider visiting the [official documentation](<https://fkhadra.github.io/react-toastify/introduction>).

## Setting Up React stateful notifications

Stateful notifications track the status of notifications, distinguishing between those that have been read and those that are new. This status is managed on both the client side (front-end) and the server side (back-end).

Stateful notifications are delivered through various channels such as **Email**, **SMS**, **Chat**, **Push**, and **In-App** notifications. The choice of channels depends on your product’s use case and available resources.

## In-App notifications

**In-App** notifications, also known as **embedded alerts**, **notification feeds**, **inboxes**, or **integrated messages**, are stateful notification channels used in React applications to provide **[real-time ](<https://novu.co/blog/live-event-alert-system/>)**[ updates](<https://novu.co/blog/live-event-alert-system/>) directly within the application’s interface.

These notifications enhance user engagement by delivering timely information in a non-disruptive manner. While they are visible during active use of the application, they can also be stored in a dedicated section for later access.

## Open source stateful notifications solutions

## novu (GitHub) (Demo)

**novu** provides a unified API that makes it simple to send notifications through multiple channels, including In-App, Push, Email, SMS, and Chat. With Novu, you can create custom workflows and define conditions for each channel, ensuring that your notifications are delivered in the most effective way possible.

- **GitHub stars:** 33.8k

- **Features:**

  - **Pre-built UI components**Novu provides pre-built, ready-to-use, and customizable UI components for in-app notifications. This can significantly reduce development time and effort.

  - **Headless option**For developers who prefer more control, Novu offers a headless component that can be used to add in-app notifications to any platform. This flexibility allows for greater customization.

  - **Multi-tab support**Novu’s in-app notifications provide a multi-tab notification experience, ensuringconsistency across different tabs of your application.

  - **Security**You can secure your connection using HMAC encryption. This adds an extra layer of security to your in-app notifications.

  - **Backend SDK methods**Novu provides backend SDK methods to support in-app notifications. This allows for seamless integration between your backend and the in-app notification system.

  - **Integration with multiple channels**Novu supports multiple notification channels including email, SMS, push, and chat, in addition to in-app notifications. This allows for a comprehensive notification strategy across various channels.

  - **Workflow management**Novu allows you to create notification workflows, which can include in-app notifications as part of a larger notification strategy.

  - **Analytics and logs**Novu provides insights into logs and analytics, which can help you optimize your notification experience.

  - **Scalability**Novu’s infrastructure is designed to handle high-volume notification delivery and storage.

  - **Compliance and security**Novu prioritizes compliance with industry standards and maintains robust security measures to protect your data.

  - **Inbox component**The Inbox component, also referred to as a widget, provides a smooth andattractive in-app notification experience for users in web applications.

  - **Multi-device real-time notifications**Novu’s in-app component offers a multi-device real-time notification experience powered by web sockets.

  - **Customizable UI**The in-app component is highly customizable to match your product’s design system.

  - **Subscriber preferences management**Users can manage their notification preferences directly from the in-app component.

  - **Multiple programming language support**Novu supports integration with multiple programming languages, includingPython, Go, Ruby, PHP, and Kotlin, allowing developers to create applications with complex notification systems.

  - **UI libraries support**Novu provides support for various UI libraries, including:

  - **Feeds**In-app notifications can be grouped into different feeds or tabs. Each message can be assigned to one specific feed.

  - **Notification actions**The in-app component supports notification actions, which are CTA buttons below the notification content that can be clicked to perform actions or external API calls.

  - **Redirect URL**Notifications can be configured to redirect users to a specific URL when clicked.

## Recommendations for stateful notifications

Before building a custom React notification system, it’s crucial to understand the potential challenges and hidden costs involved.

A comprehensive React notification system often needs to include web push, mobile push, SMS, and email notifications. Each type requires specific implementations and permission-based systems.

Moreover, handling user data for SMS and email must comply with privacy laws like GDPR and CCPA.

**Developers typically spend only about 31% of their time writing code when building a custom notification system. **

The remaining time is consumed by managing multiple custom implementations for different browsers and devices, which adds to the workload.

After implementation, A/B testing is necessary to optimize content and timing, requiring proper data storage and analysis.

While custom solutions offer control over design and implementation, they can be more trouble than they are worth. Unless notifications are central to your business, building and maintaining an in-house system is a significant commitment for any development team.

Novu is the only open-source solution that provides an end-to-end solution. It offers options to self-host the entire infrastructure, use only the [In-App ready-to-use](<https://docs.novu.co/inbox/react/api-reference>) or [headless component functionality](<https://docs.novu.co/inbox/headless/get-started>), or handle all your current and future notification needs.

## Stateful notifications implementation

## Requirements

[React](<https://reactjs.org/>) version &gt;= 16.8 or above

## Installation

With npm:

```bash
npm install @novu/notification-center
```

With yarn:

```bash
yarn add novu/notification-center
```

## The gist

```javascript
import {
  NovuProvider,
  PopoverNotificationCenter,
  NotificationBell,
  IMessage,
} from "@novu/notification-center";

function Novu() {
  return (

        {({ unseenCount }) => }
      </PopoverNotificationCenter>
    </NovuProvider>
  );
}
```

- `NovuProvider`: This component wraps your application and provides the necessary context for Novu to work.

- `PopoverNotificationCenter`: This component creates a popover that contains the notification center.

**Important notes**

- `NotificationBell`: This component renders the notification bell icon, which displays the number of unseen notifications.

  - Replace `"SUBSCRIBER_ID"` with the actual subscriber ID for the user.

  - Replace `"APPLICATION_IDENTIFIER"` with your Novu application identifier.

## Best practices

**Consistent usage**

- Ensure that the `NovuProvider` wraps your entire application to provide the necessary context for the notification system.

- Use the `PopoverNotificationCenter` to create a popover containing the notification center, and the `NotificationBell` to render the notification bell icon.

- Replace `"SUBSCRIBER_ID"` and `"APPLICATION_IDENTIFIER"` with the actual values for your users and application.

- Customize the `colorScheme` prop on `PopoverNotificationCenter` to fit your application’s design.

**User experience**

- Keep the notification bell icon visible and easily accessible to users.

- Use `onNotificationClick` to handle what happens when a user clicks on a notification, ensuring a seamless navigation experience.

- Utilize `onActionClick` to manage actions within notifications, such as accepting friend requests or other interactive elements.

- Implement HMAC encryption to secure the `subscriberId` and prevent malicious access to user feeds.

- Provide real-time updates using the `useSocket` hook to keep users informed about new notifications immediately.

## Customization

**PopoverNotificationCenter customization**

`&lt;PopoverNotificationCenter&gt;` is a pre built notification center component that can be used to show notifications in your application. It is a popover component that can be placed anywhere in your application. A bell will appear on the page. On click of that bell, a popover will appear. Checkout all customizations and available [props](<https://www.notion.so/notification-center/client/react/api-reference#popovernotificationcenter>). If you are looking for a component without popover use regular `&lt;NotificationCenter&gt;` component. Checkout [props](<https://www.notion.so/notification-center/client/react/api-reference#notificationcenter>) of this component. Few selected customization options are explained below:-

**Implementing custom bell icon**

It is common that you might have a special set of icons you use within your application and you will want to replace the default: `NotificationBell` coming from our library.

For this you can easily switch the `NotificationBell` with your own bell. Just make sure you pass the `unseenCount` param inside and use it accordingly.

```javascript
{({ unseenCount }) => (

  )}
</PopoverNotificationCenter>
```

**Dark mode support**

To support dark mode in your application the notification center component can receive a `colorScheme` prop that can receive either `dark` or `light` mode.

```javascript
{({ unseenCount }) => }
</PopoverNotificationCenter>
```

**Popover positioning**

Use `position`  and `offset` prop to position the popover relative to the Bell icon

```javascript
{({ unseenCount }) => }
</PopoverNotificationCenter>
```

**Header, footer and empty state**

Use `header`, `footer` and `emptyState` prop to customize the header, footer and empty state of notification center.

```javascript
const Header = () => {
  return  My custom header </span>;
};

const Footer = () => {
  return  My custom footer </span>;
};

const EmptyState = () => {
  return  My custom empty state </span>;
};

 }
  footer={() => }
  emptyState={}
>
  {({ unseenCount }) => }
</PopoverNotificationCenter>;
```

**Notification item**

Use the `listItem` prop to show custom notification items.

```javascript
{
    return (
       {
          e.preventDefault();
          handleNotificationClick();
        }}
      >
        {notification.content}
      </a>
    );
  }}
>
  {({ unseenCount }) => {
    return ;
  }}
</PopoverNotificationCenter>
```

**Customize the UI language**

If you want to use a language other than english for the UI, the `NovuProvider` component can accept an optional `i18n` prop.

```javascript
{({ unseenCount }) => }
  </PopoverNotificationCenter>
</NovuProvider>
```

The `i18n` prop can accept 2 different types of values 2 letter language string.

```javascript
i18n = "en";
```

Translation object

```javascript
i18n={{
  // Make sure that the following is a proper language code,
  // since this is used by Intl.RelativeTimeFormat in order to calculate the relative time for each notification
  //
  lang: "de",

  translations: {
    poweredBy: "von",
    markAllAsRead: "Alles als gelesen markieren",
    notifications: "Benachrichtigungen",
    settings: "Einstellungen",
  },
}}
```

**Customization using ****`styles`**** prop**

`styles` prop can be used to customize styling of each component of notification center.

Read more about [styles prop](<https://www.notion.so/notification-center/client/react/api-reference#styles>)

```javascript
export const styles = {
  bellButton: {
    root: {
      marginTop: "20px",
      svg: {
        color: "#AFE1AF",
        fill: "white",
        minWidth: "20px",
        minHeight: "20px",
      },
    },
    dot: {
      rect: {
        fill: "white",
        strokeWidth: "0",
        width: "3px",
        height: "3px",
        x: 10,
        y: 2,
      },
    },
  },
};
```

**Customizing styles**

```javascript
const primaryColor = "white";
const secondaryColor = "#AFE1AF";
const primaryTextColor = "#0C0404";
const secondaryTextColor = "#494F55";
const unreadBackGroundColor = "#869F9F";
const primaryButtonBackGroundColor = unreadBackGroundColor;
const secondaryButtonBackGroundColor = "#C6DFCD";
const dropdownBorderStyle = "2px solid #AFE1AF";
const tabLabelAfterStyle = "#AFE1AF !important";
const ncWidth = "350px !important";

export const styles = {
  bellButton: {
    root: {
      marginTop: "20px",
      svg: {
        color: secondaryColor,
        fill: primaryColor,
        minWidth: "20px",
        minHeight: "20px"
      }
    },
    dot: {
      rect: {
        fill: primaryColor,
        strokeWidth: "0",
        width: "3px",
        height: "3px",
        x: 10,
        y: 2
      }
    }
  },
  unseenBadge: {
    root: { color: primaryTextColor, background: secondaryColor }
  },
  popover: {
    root: { zIndex: -99 },
    arrow: {
      backgroundColor: primaryColor,
      borderLeftColor: secondaryColor,
      borderTopColor: secondaryColor
    },
    dropdown: {
      border: dropdownBorderStyle,
      borderRadius: "10px",
      marginTop: "25px",
      maxWidth: ncWidth
    }
  },
  header: {
    root: {
      backgroundColor: primaryColor,
      "&:hover": { backgroundColor: primaryColor },
      cursor: "pointer",
      color: primaryTextColor
    },
    cog: { opacity: 1 },
    markAsRead: {
      color: primaryTextColor,
      fontSize: "14px"
    },
    title: { color: primaryTextColor },
    backButton: {
      color: primaryTextColor
    }
  },
  layout: {
    root: {
      background: primaryColor,
      maxWidth: ncWidth
    }
  },
  loader: {
    root: {
      stroke: primaryTextColor
    }
  },
  accordion: {
    item: {
      backgroundColor: secondaryColor,
      ":hover": {
        backgroundColor: secondaryColor
      }
    },
    content: {
      backgroundColor: secondaryColor,
      borderBottomLeftRadius: "7px",
      borderBottomRightRadius: "7px"
    },
    control: {
      ":hover": {
        backgroundColor: secondaryColor
      },
      color: primaryTextColor,
      title: {
        color: primaryTextColor
      }
    },
    chevron: {
      color: primaryTextColor
    }
  },
  notifications: {
    root: {
      ".nc-notifications-list-item": {
        backgroundColor: secondaryColor
      }
    },
    listItem: {
      layout: {
        borderRadius: "7px",
        color: primaryTextColor,
        "div:has(> .mantine-Avatar-root)": {
          border: "none",
          width: "20px",
          height: "20px",
          minWidth: "20px"
        },
        ".mantine-Avatar-root": {
          width: "20px",
          height: "20px",
          minWidth: "20px"
        },
        ".mantine-Avatar-image": {
          width: "20px",
          height: "20px",
          minWidth: "20px"
        }
      },
      timestamp: { color: secondaryTextColor, fontWeight: "bold" },
      dotsButton: {
        path: {
          fill: primaryTextColor
        }
      },
      unread: {
        "::before": { background: unreadBackGroundColor }
      },
      buttons: {
        primary: {
          background: primaryButtonBackGroundColor,
          color: primaryTextColor,
          "&:hover": {
            background: primaryButtonBackGroundColor,
            color: secondaryTextColor
          }
        },
        secondary: {
          background: secondaryButtonBackGroundColor,
          color: secondaryTextColor,
          "&:hover": {
            background: secondaryButtonBackGroundColor,
            color: secondaryTextColor
          }
        }
      }
    }
  },
  actionsMenu: {
    item: { "&:hover": { backgroundColor: secondaryColor } },
    dropdown: {
      backgroundColor: primaryColor
    },
    arrow: {
      backgroundColor: primaryColor,
      borderTop: "0",
      borderLeft: "0"
    }
  },
  preferences: {
    item: {
      title: { color: primaryTextColor },
      divider: { borderTopColor: primaryColor },
      channels: { color: secondaryTextColor },
      content: {
        icon: { color: primaryTextColor },
        channelLabel: { color: primaryTextColor },
        success: { color: primaryTextColor }
      }
    }
  },
  tabs: {
    tabLabel: {
      "::after": { background: tabLabelAfterStyle },
      ":hover": { color: tabLabelAfterStyle },
      "[data-active]": { color: tabLabelAfterStyle }
    },
    tabsList: { borderBottomColor: primaryColor }
  }
};
```

**Customization using hooks**

If you don’t want to use our pre built component then, you can build your own notification center using hooks. `@novu/notification-center` react package provides many hooks like `useNotifications`, `useFetchNotifications`, `useUpdateUserPreferences`. Checkout all available [hooks](<https://www.notion.so/notification-center/client/react/api-reference#hooks>). All the hooks should be defined inside the [NovuProvider](<https://www.notion.so/notification-center/client/react/api-reference#novuprovider>) component. Most of the hooks are based on the `@tanstack/react-query` library.

To learn more about how to customize and style your In-App Inbox component, visit [this page](<https://github.com/novuhq/docs/blob/main/inbox/react/customization.mdx>).

## Testing

You can use testing libraries like React Testing Library and Jest. Here is an example of how you can write tests for this component:

**1. Install the necessary dependencies**

```javascript
npm install @testing-library/react @testing-library/jest-dom jest
```

**2. Create a test file for the ****`Novu`**** component**, for example `Novu.test.js`

```javascript
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { NovuProvider, PopoverNotificationCenter, NotificationBell } from '@novu/notification-center';
import Novu from './Novu';

jest.mock('@novu/notification-center', () => ({
  NovuProvider: jest.fn(({ children }) => {children}</div>),
  PopoverNotificationCenter: jest.fn(({ children }) => children({ unseenCount: 5 })),
  NotificationBell: jest.fn(({ unseenCount }) => {`Unseen Count: ${unseenCount}`}</div>),
}));

describe('Novu component', () => {
  test('renders NovuProvider with correct props', () => {
    render();
    expect(NovuProvider).toHaveBeenCalledWith(
      expect.objectContaining({
        subscriberId: 'SUBSCRIBER_ID',
        applicationIdentifier: 'APPLICATION_IDENTIFIER',
      }),
      expect.anything()
    );
  });

  test('renders PopoverNotificationCenter with dark colorScheme', () => {
    render();
    expect(PopoverNotificationCenter).toHaveBeenCalledWith(
      expect.objectContaining({
        colorScheme: 'dark',
      }),
      expect.anything()
    );
  });

  test('renders NotificationBell with correct unseenCount', () => {
    render();
    expect(screen.getByText('Unseen Count: 5')).toBeInTheDocument();
  });
});
```

**3. Run your tests**

```javascript
npm test
```

**Explanation**

This test setup does the following:

- Mocks the `NovuProvider`, `PopoverNotificationCenter`, and `NotificationBell` components from `@novu/notification-center`.

- Checks if the `NovuProvider` component is rendered with the correct props.

- Checks if the `PopoverNotificationCenter` component is rendered with the `dark` color scheme.

- Checks if the `NotificationBell` component is rendered with the correct `unseenCount`.

This should give you a good starting point for testing your `Novu` component.

**Additional tests**

You can also consider a variety of test cases, including rendering tests, interaction tests, and state management tests.

Below are some additional tests you could apply:

**Rendering tests**

- Ensure the component renders correctly with initial state.

- Verify that the notification feed list renders the correct number of notifications.

- Check that each notification item displays the expected content (e.g., title, message, timestamp).

**Interaction tests**

- Test that clicking on a notification item triggers the appropriate action (e.g., marking as read, opening a detail view).

- Ensure the notification bell updates correctly when notifications are read or new notifications arrive.

- Verify that the popover opens and closes correctly when the notification bell is clicked.

**State Management tests**

- Check that the component correctly handles state changes, such as loading, success, and error states.

- Ensure that notifications are correctly added, updated, or removed from the feed.

- Verify that unread notifications are accurately counted and displayed.

**API Integration tests**

- Mock API responses to ensure the component correctly handles different responses (e.g., successful data fetch, empty list, error response).

- Ensure that the component initiates the correct API calls on mount and when interactions occur.

**Accessibility tests**

- Verify that the component is accessible, including proper ARIA roles, keyboard navigation, and focus management.

**Snapshot tests**

- Create snapshot tests to ensure the UI does not change unexpectedly.

**Integration with CI/CD**

Ensure that your tests are integrated with your CI/CD pipeline to automatically run these tests on every push or pull request. This helps catch any issues early and maintains the reliability of your notifications.

In case you would like to get even more into how to customize and have a better understanding overall, consider visiting the [official documentation](<https://docs.novu.co/inbox/introduction>).

Table of contents

- [Introduction to React notifications](<#ad5d1db2-3190-409a-a785-994f8f7b6700>)

  - [What are notifications?](<#667d1d67-41d6-410e-be31-199d990182e0>)

    - [Important considerations](<#c28e4692-d624-418f-8a78-c883d59e83a1>)

  - [Types of notifications in React](<#8df719d0-5c0a-4794-83ed-a1a058beb220>)

    - [Stateless notifications](<#3db015e2-f75d-4a30-8667-20c9752d3746>)

    - [Stateful notifications](<#f0773085-3bab-4cb2-be9b-513e3df68c95>)

    - [Notification type comparison](<#5c7b4394-5f86-4eac-af9e-1d1138b738bc>)

  - [Setting up React stateless notifications](<#a019073a-4cf5-4b4e-ae4f-8a7217e41f09>)

    - [Pop-up notifications](<#95ea17a1-195a-40b8-ae94-0e5cfe9b5311>)

    - [Modal notifications](<#19a29526-382d-4590-a9a9-f8a176970602>)

  - [Open source stateless notifications solutions](<#4e7ed69a-29c3-4c91-8ce1-30252e10d746>)

    - **[react-toastify](<#e0c25989-c8c7-4760-8277-8a0bdd1f8bdf>)**

    - **[react-hot-toast](<#d8a065b4-4676-4a5f-8ad3-ee5fcb0ab849>)**

    - **[notistack](<#bed77970-f00d-44d8-914d-684a31bfa422>)**

    - **[react-notification-system](<#1be4c8dc-fb91-43aa-a64d-662a48624d3d>)**

    - **[react-toast-notifications](<#8de64dfe-45c8-44e4-820a-128c948394a1>)**

    - **[reapop](<#d53a0c3a-8774-4deb-b4ab-4dd61a2c31cd>)**

    - **[react-notifications-component](<#59e5bddc-f44f-4014-9831-4a9e0533f30b>)**

    - **[react-redux-toastr](<#0a2cdc01-e3ec-4a51-80e4-91a017125968>)**

    - **[notiflix](<#51fad301-45a9-4d8c-82c3-1fb7be6a7d1e>)**

    - **[react-modal](<#d8a697df-497e-47c7-829b-ba5bb85964b2>)**

    - react-aria

  - [Recommendations for stateless notifications](<#364c3c26-e000-4d73-b501-ca66d2613fda>)

  - [Stateless notifications implementation](<#cb217743-6f12-4615-b551-d0633f89478e>)

    - **[Requirements](<#38825390-f777-44de-ab9c-9a87c4f14c4e>)**

    - **[Installation](<#046bb31d-f9e9-4f33-935c-e742f373062a>)**

    - **[The gist](<#217844ed-b006-4e2b-91c9-fcbde3ba6dc3>)**

    - [Best practices](<#f28e2e6a-182f-4169-a7f8-70b6c38be3d4>)

    - [Customization](<#45feadd5-1ee7-42cf-b956-4f22af398c8c>)

    - [Testing](<#bdac9ea5-1d35-4d1a-9fb1-f1a052232727>)

  - [Setting Up React stateful notifications](<#64973d58-3cd6-4f7f-8a5c-91f876d4b8d6>)

    - [In-App notifications](<#cd362583-e060-4144-8f8d-49a309660ce9>)

  - [Open source notification solutions](<#ae645d70-0382-4c32-9b0f-cf3a829b928b>)

    - [Novu](<#d2041515-16d4-46ea-b81b-52d667e40c00>)

  - [Recommendations for stateful notifications](<#c53a2e95-72d1-4fe1-9f13-8e630b4d84b9>)

  - [Stateful notifications implementation](<#37887bf5-1c59-4562-b194-0ee0d5610327>)

    - **[Requirements](<#63084950-5b1a-489c-a309-7d06c8a265dc>)**

    - **[Installation](<#09289f85-d01f-4645-9ade-a9e66cc1dbf6>)**

    - **[The gist](<#c34b3a38-1277-4942-bfcd-8003b8035a2d>)**

    - [Best practices](<#4cad7490-95cd-4df3-9e71-00536ce4685f>)

    - [Customization](<#c7942d6e-5dd3-4b40-9d0a-699dd32ad02f>)

    - [Testing](<#85482483-d4b4-43dd-8c78-6626528c05bb>)

Table of contents

**2. Create a test file for the ****`Novu`**** component**, for example `Novu.test.js`
