Daisy UI is a modern, accessible, and customizable UI component library for React. In this tutorial, the problem is daisy ui only provides css styles and no js functionality, so we will create a custom toast library using daisy ui for the styles and Zustand for the state management.
this is what dasiy ui provide's
<div className="toast">
<div className="alert alert-info">
<span>New message arrived.</span>
</div>
</div>
now Lets add some js functionality to it
Prerequisites
Before we begin, ensure you have the following prerequisites in place:
- Basic knowledge of React
- Node.js installed on your machine
- A code editor (e.g., VS Code)
- Tailwind CSS installed in your project
Setting Up the Project
To get started, create a new React project using Vite
npm create vite@latest
Setup tailiwnd css
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
npm i -D daisyui@latest
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [require("daisyui")],
// setup a theme for daisy ui
daisyui: {
themes: ["light", "dark"],
},
};
/* index.css || app.css || styles.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Our project is setup with tailwind css and daisy ui now lets setup zustand for state management
npm i zustand
Creating the Toast Store
Create a new file called toastStore.js
in the src/lib/store.ts
directory and add the following code:
// src/lib/store.ts
import { create } from "zustand";
export type ToastType = "success" | "error" | "info" | "warning";
export interface IToast {
id: string;
message: string;
type: ToastType;
}
interface ToastStore {
toast: IToast[];
addTost: (toast: IToast) => void;
removeToast: (id: string) => void;
}
export const useToastStore =
create <
ToastStore >
((set) => ({
toast: [],
addTost: (toast: IToast) =>
set((state) => ({ toast: [...state.toast, toast] })),
removeToast: (id: string) =>
set((state) => ({ toast: state.toast.filter((t) => t.id !== id) })),
}));
Creating the Toast Component
Create a new file called Toast.tsx
in the src/components/Toast/ToastContainer/index.ts
directory and add the following code:
// src/components/Toast/ToastContainer/index.ts
import { useToastStore } from "@/lib/store";
import { useEffect } from "react";
function ToastContainer({ toastTimer = 2000 }: { toastTimer?: number }) {
const toasts = useToastStore((state) => state.toast);
const removeToast = useToastStore((state) => state.removeToast);
// remove toast after 2 seconds
useEffect(() => {
const timer = setTimeout(() => {
if (toasts.length > 0) {
const id = toasts[0].id;
useToastStore.getState().removeToast(id);
}
}, toastTimer);
return () => clearTimeout(timer);
}, [toastTimer, toasts]);
return (
<div className="toast toast-end">
{toasts.map((toast) => {
return (
<div
key={toast.id}
className={`alert flex justify-between ${
toast.type === "success"
? "alert-success"
: toast.type === "error"
? "alert-error"
: toast.type === "info"
? "alert-info"
: "alert-warning"
}`}
>
<span className="text-xl px-5 text-start">{toast.message}</span>
<button
className="btn btn-ghost"
onClick={() => removeToast(toast.id)}
>
X
</button>
</div>
);
})}
</div>
);
}
export default ToastContainer;
Creating a Hook to Add Toasts
Create a new file called useToast.ts
in the src/hooks/useToast.tsx
directory and add the following code:
// src/hooks/useToast.tsx
import { useToastStore } from "@/lib/store";
import { ToastType } from "@/types";
const useToast = () => {
const { addToasts } = useToastStore((state) => ({
addToasts: state.addTost,
}));
const showToast = {
success: (message: string) =>
addToasts({ id: Math.random().toString(),message, type: "success" as ToastType}),
warning: (message: string) =>
addToasts({ id: Math.random().toString(), message, type: "warning" as ToastType}),
error: (message: string) =>
addToasts({ id: Math.random().toString(), message, type: "error" as ToastType}),
info: (message: string) =>
addToasts({ id: Math.random().toString(), message, type: "info" as ToastType}),
};
return showToast;
};
export default useToast;
Add ToastContainer to App or Layout
function Layout({ children }: { children: ReactNode }) {
return (
<div className="min-w-screen overflow-x-hidden">
<Navbar />
{children}
<ToastContainer />
<Footer />
</div>
);
}
export default Layout;
Now you can use the useToast hook to add toasts in your components
function Home() {
const toast =useToast();
toast.success('msg')
toast.error('msg')
toast.info('msg')
toast.warning('msg')
return(
///
)
}
Conclusion
In this tutorial, we've explored how to create a custom toast library in React using Daisy UI for the styles and Zustand for state management. By following the steps outlined in this guide, you can enhance the user experience of your React applications by adding toast notifications that provide feedback to users in a visually appealing and unobtrusive manner. Implementing a custom toast library can help you streamline the process of displaying notifications and alerts in your applications, making them more user-friendly and engaging.