Create Notification.tsx file
import { CheckCircleIcon, ExclamationCircleIcon, InformationCircleIcon, XCircleIcon, XIcon } from '@heroicons/react/outline';
import { AnimatePresence, motion } from 'framer-motion';
import { nanoid } from 'nanoid';
import { createContext, useContext, useState, ReactNode, useCallback, FC } from 'react';
interface NotificationProps {
  type?: 'success' | 'error' | 'warning' | 'info'
  title: string
  description: string
  duration?: number
}
export type NotificationRenderFunction = FC<NotificationProps & {onClose: () => void}>
export interface NotifyOptions extends NotificationProps {
  render?: NotificationRenderFunction
}
interface NotificationI extends NotifyOptions {
  id: string
  onClose: () => void
}
interface NotificationContextI {
  notify: (options: NotifyOptions) => void
}
const NotificationContext = createContext<NotificationContextI>({} as NotificationContextI);
export function useNotify() {
  return useContext(NotificationContext);
}
interface NotificationProviderProps {
  children: ReactNode
}
function useNotifications() {
  const [notifications, setNotifications] = useState<NotificationI[]>([]);
  const notify = useCallback((options: NotifyOptions): void => {
    const id = nanoid();
    function removeNotification() {
      setNotifications(notifications => notifications.filter(n => n.id !== id));
    }
    const newNotification = {
      ...options,
      id,
      onClose: removeNotification
    };
    setNotifications(notifications => [newNotification, ...notifications]);
    setTimeout(removeNotification, options.duration || 3000);
  }, []);
  return { notify, notifications };
}
function NotificationProvider({ children }: NotificationProviderProps) {
  
  const { notify, notifications } = useNotifications();
  return (
    <NotificationContext.Provider value={{ notify }}>
      <div className="fixed sm:flex sm:flex-col sm:items-end px-5 w-full top-5 sm:w-auto sm:right-5 sm:px-0 z-50">
        <AnimatePresence>      
          {notifications.map(n => <Notification key={n.id} {...n} />)}
        </AnimatePresence>
      </div>
      {children}
    </NotificationContext.Provider>
  );
}
const icons = {
  success: <CheckCircleIcon className="w-6 h-6 text-green-400 mt-1" />,
  error: <XCircleIcon className="w-6 h-6 text-red-400 mt-1"/>,
  warning: <ExclamationCircleIcon className="w-6 h-6 text-yellow-400 mt-1" />,
  info: <InformationCircleIcon className="w-6 h-6 text-blue-400 mt-1" />
};
function Notification({ render: Render, id, ...props }: NotificationI) {
  return (
    <motion.div
      key={id}
      initial={{ opacity: 0, scale: 0.8, x: 300 }} // animate from
      animate={{ opacity: 1, scale: 1, x: 0 }} // animate to
      exit={{ opacity: 0, scale: 0.8, x: 300 }} // animate exit
      // describe transition behavior
      transition={{
        type: 'spring',
        stiffness: 500,
        damping: 40,
      }} 
      // auto animates the element when it's position changes
      layout
    >
      {Render ?
        <Render {...props} />
        :
        <div className="bg-gray-100 dark:bg-gray-800 w-full sm:w-80 mb-4 text-gray-900 dark:text-gray-50 shadow-md flex py-2 px-4 rounded-lg space-x-4">
          <div>
            {icons[props.type || 'success']}
          </div>
          <div className="flex-grow">
            <h3 className="text-lg font-medium">{props.title}</h3>
            <p className="text-md">{props.description}</p>
          </div>
          <div>
            <button onClick={props.onClose} className="hover:bg-gray-200 dark:hover:bg-gray-700 p-1 rounded-md focus:outline-none focus:ring-offset-1 focus:ring-offset-transparent focus:ring-1 focus:ring-indigo-400">
              <XIcon className="w-6 h-6 text-gray-900 dark:text-gray-50" />
            </button>
          </div>
        </div>}
    </motion.div>
  );
}
export default NotificationProvider;Wrap your entire app with NotificationProvider
function App({ Component, pageProps }: AppProps) {
  return (
    <NotificationProvider>
      <Component {...pageProps} />
    </NotificationProvider>
  );
}
In every component you want is possible to spawn a notification
const { notify } = useNotify();
notify({
  title: 'Welcome! 🚀',
  description: 'Your account has been succesfully created.',
  type: 'success',
  duration: 5000
});
Define a custom notification
export default const MyNotification: NotificationRenderFunction = ({ title, description, onClose, duration, type }) => {
  return (
    <div className="mb-4 p-4 bg-indigo-300 text-gray-900 flex space-x-2 justify-between items-start">
      <div>
        <h1 className="text-lg font-semibold italic">{title}</h1>
        <p>{description}</p>
      </div>
      <button onClick={onClose}>
        <XIcon className="w-6 h-6" />
      </button>
    </div>
  );
};
import MyNotification from './MyNotification.tsx';
const { notify } = useNotify();
notify({
  title: 'Welcome! 🚀',
  description: 'Your account has been succesfully created.',
  duration: 5000,
  render: MyNotification
});