Mastering UI Theming in Next 14 with DaisyUI: Set up multiple Daisy theme( dark, custom , …) in next 14

Amir Moradnejad
5 min readDec 1, 2023

--

DaisyUI’s theme capabilities go beyond the traditional light/dark mode distinction. To apply a specific theme, simply add data-theme="your-theme-name" to the root HTML element. DaisyUI, a robust CSS library, significantly streamlines component creation in Tailwind CSS by requiring fewer classes compared to the base Tailwind CSS library.

This tutorial will walk you through integrating DaisyUI themes into Next.js 14 or React. This setup will store theme data in local storage, ensuring that users’ theme preferences persist across browser sessions

Install and Configure DaisyUI in Next14

Step1: Install DasiyUI

npm install -D daisyui

step2: Configure DaisyUI in Tailwind CSS inside the Next14 project

Next, open your tailwind.config.js file and add the following configuration:

module.exports = {
// ... your existing Tailwind CSS configuration
plugins: [
require('daisyui'),
],

};

This configuration tells Tailwind CSS to use DaisyUI and enables the ability to use DaisyUI themes.

step3: Choose Your Theme

DaisyUI comes with many themes, which you can use with no extra effort. Each theme defines a set of colors that will be used on all daisyUI elements. You can see the list of DaisyUI themes from DaisyUI themes list. To use a theme, add its name in tailwind.config.ts like this cod:

import type { Config } from "tailwindcss";

const config: Config = {
...

plugins: [require("daisyui")],
daisyui: {
themes: [ // list theme you want to use in your project.
"light",
"dark",
"retro",
"aqua ",
},
],
},
};
export default config;

So we set all DasyUI Theme config for the Next 14 now we can start Coding

step 4: Create a ThemContext

Establish a React context for managing theme status and create a ThemeProvider component to provide and consume the theme context value.

// ThemeContext.tsx
import { createContext, useEffect, useState } from "react";

interface ThemeContextType {
theme?: string;
changeTheme?: (nextTheme?: string) => void;
}

export const ThemeContext = createContext<ThemeContextType>({});

export const ThemeProvider = ({ children }: any) => {
// ... (Refer to your provided code for the detailed implementation)
};
export const ThemeContext = createContext<ThemeContextType>({});

This line creates a new React context named ThemeContext using the createContext function. The initial value for this context is an empty object, which matches the structure of the ThemeContextType interface.

To provide the theme context value to its children we can write ThemeProvider Component:

export const ThemeProvider = ({ children }: any) => {
const [theme, setTheme] = useState<string>(
() => localStorage.getItem("theme") || "light"
);

useEffect(() => {
localStorage.setItem("theme", theme);
}, [theme]);

const changeTheme = (event?: any) => {
const nextTheme: string | null = event.target.value || null;
if (nextTheme) {
setTheme(nextTheme);
} else {
setTheme((prev) => (prev === "light" ? "dark" : "light"));
}
};
return (
<ThemeContext.Provider value={{ theme, changeTheme }}>
{children}
</ThemeContext.Provider>
);

Finaly the ThemeContext.tsx file code :

"use client";
import { createContext, useEffect, useState } from "react";
import { ThemeType } from "@/app/types";
import Loading from "@/app/loading";

interface ThemeContextType {
theme?: string;
changeTheme?: (nextTheme?: string) => void;
}
export const ThemeContext = createContext<ThemeContextType>({});

export const ThemeProvider = ({ children }: any) => {
const [theme, setTheme] = useState<string>(
() => localStorage.getItem("theme") || "light"
);

useEffect(() => {
localStorage.setItem("theme", theme);
}, [theme]);

const changeTheme = (event?: any) => {
const nextTheme: string | null = event.target.value || null;
if (nextTheme) {
setTheme(nextTheme);
} else {
setTheme((prev) => (prev === "light" ? "dark" : "light"));
}
};
return (
<ThemeContext.Provider value={{ theme, changeTheme }}>
{children}
</ThemeContext.Provider>
);
}

The “use clinet” in the head of the ThemeContext component mention the componet is clinet-side component. In Next 14 the Client Components allows you to write interactive UI that can be rendered on the client at request time

step 5: Apply Theme to HTML

To apply a specific theme, simply add data-theme="your-theme-name" to the root HTML element

Create a ClientThemeWrapper.tsx file to add a data-theme attribute to all HTML nodes.

// ClientThemeWrapper.tsx
"use client";
import { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

export default function ClientThemeWrapper({ children }: any) {
// ... (Refer to your provided code for the detailed implementation)
}

step 6 : Add ThemeProvider and ClientThemeWrapper in to layout

Update your layout.tsx file to include ThemeProvider and ClientThemeWrapper for a seamless theme experience like this code :

//layout.tsx
......
return (
<html lang="en">
<body className={inter.className}>
<ThemeProvider>
<ClientThemeWrapper>
<div className="max-w-5xl mx-auto text-2xl pt-4 h-screen">
<NavBar />
{children}
</div>
</ClientThemeWrapper>
</ThemeProvider>
</body>
</html>
);

step 7 : Implement Theme Controller.

Utilize DaisyUI ThemeContrller or design your button to allow users to change theme status dynamically.

DasiyUI Theme Controller using a dropdown

Source Code:

Git source Code of Next 14 multiple Them with DaisyUI

Conclusion:

In conclusion, this guide has equipped you with the tools to master UI theming in Next.js 14 using DaisyUI. By following our step-by-step instructions and exploring a practical example of setting up multiple themes, including a dark theme and a custom theme, you’ve gained valuable insights into enhancing the visual appeal and user experience of your web applications.

The integration of DaisyUI not only simplifies the process of creating components in Tailwind CSS but also offers versatile theming capabilities beyond the conventional light/dark mode. The provided Git code serves as a valuable resource, allowing you to implement the concepts discussed in this guide seamlessly.

As you continue to refine and customize your themes, remember that a well-designed UI contributes significantly to user engagement and satisfaction. Whether you choose predefined themes or create your own, the flexibility provided by DaisyUI empowers you to tailor your application’s look and feel according to your preferences and brand identity.

Now, armed with the knowledge and practical experience shared in this guide, you’re ready to embark on a journey of crafting visually stunning and user-friendly interfaces in your Next.js 14 projects.

Happy theming!

--

--