DEV Community

JAKER HOSSAIN
JAKER HOSSAIN

Posted on

Create Reusable Toaster Notifications in React with Custom Animations

Learn how to build a reusable toaster component in React that supports different notification types like success, error, and warning. It includes features like smooth fade-out animations, progress bars, and customizable positions. This is a quick and effective way to improve user experience in your web applications by providing non-intrusive notifications.

šŸ“¢ Key Features:

šŸŽ‰ Customizable Notification Types: Choose from success, error, warning, and info.
šŸš€ Smooth Animations: Includes slide-in and fade-out animations.
šŸ“ Position Control: Place the notification at any corner of the screen.
ā³ Progress Bar: Visualize the time remaining before the notification disappears.
ā²ļø Adjustable Duration: Set how long the notification stays visible.

"use client";
import { IconX } from "@tabler/icons-react";
import React, { useEffect, useState } from "react";
import styles from "./Toaster.module.css";

const Toaster = ({
  message,
  duration = 3,
  onClose,
  type = "success",
  position = "top-right",
  toasterStyle,
  progressBarStyle,
}: {
  message: string;
  duration?: number;
  onClose?: () => void;
  type?: "success" | "error" | "warning" | "info";
  position?: "top-right" | "top-left" | "bottom-right" | "bottom-left";
  toasterStyle?: string;
  progressBarStyle?: string;
}) => {
  const [isVisible, setIsVisible] = useState(false);
  const [isFading, setIsFading] = useState(false);

  useEffect(() => {
    setIsVisible(true);

    const fadeTimer = setTimeout(() => {
      setIsFading(true);
    }, (duration - 0.5) * 1000);

    const closeTimer = setTimeout(() => {
      setIsVisible(false);
      if (onClose) onClose();
    }, duration * 1000);

    return () => {
      clearTimeout(fadeTimer);
      clearTimeout(closeTimer);
    };
  }, [duration, onClose]);

  const handleClose = () => {
    setIsFading(true);
    setTimeout(() => {
      setIsVisible(false);
      if (onClose) onClose();
    }, 500);
  };

  if (!isVisible) return null;

  return (
    <div
      className={`${styles.toaster} ${styles[type]} ${styles[position]} ${
        isFading ? styles["fade-out"] : ""
      } fixed rounded-md px-3 py-2 flex items-center justify-between gap-x-2  ${toasterStyle}`}
    >
      <span className="text-xs md:text-sm">{message}</span>
      <span
        onClick={handleClose}
        className="cursor-pointer transition-opacity ease-in hover:opacity-70"
      >
        <IconX className="w-4 h-4" />
      </span>
      <div
        className={`${styles["progress-bar"]} ${progressBarStyle}`}
        style={{ animationDuration: `${duration - 0.5}s` }}
      ></div>
    </div>
  );
};

export default Toaster;

Enter fullscreen mode Exit fullscreen mode
.toaster {
  z-index: 1000;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
  transform: translateX(150%);
  animation: slideIn 0.5s ease-out forwards;
  position: fixed;
  min-width: 250px;
  max-width: 400px;
  padding: 12px;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 10px;
}

.fade-out {
  animation: fadeOut 0.5s ease-in forwards;
}

.top-right {
  top: 10px;
  right: 10px;
}
.top-left {
  top: 10px;
  left: 10px;
}
.bottom-right {
  bottom: 10px;
  right: 10px;
}
.bottom-left {
  bottom: 10px;
  left: 10px;
}

.success {
  background-color: #22c55e;
  color: white;
}
.error {
  background-color: #ef4444;
  color: white;
}
.warning {
  background-color: #f59e0b;
  color: white;
}
.info {
  background-color: #3b82f6;
  color: white;
}

.progress-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 2px;
  background-color: white;
  animation: progress linear forwards;
}

@keyframes slideIn {
  from {
    transform: translateX(150%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes progress {
  from {
    width: 0%;
  }
  to {
    width: 100%;
  }
}

Enter fullscreen mode Exit fullscreen mode

Toaster notifications are a great way to keep users informed without interrupting their experience. By building a customizable toaster system in React, you can easily adapt it to fit your app's design and user needs. With features like smooth animations, customizable positions, progress bars, and adjustable durations, this simple component can significantly enhance your web application's user experience. Try implementing it in your next project for non-intrusive, yet effective notifications.

Postgres on Neon - Get the Free Plan

No credit card required. The database you love, on a serverless platform designed to help you build faster.

Get Postgres on Neon

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

šŸ‘‹ Kindness is contagious

Please leave a ā¤ļø or a friendly comment on this post if you found it helpful!

Okay