Introduction#
This demo shows how to create a Toggle Theme using only Tailwind and HTML. Then it also shows how to create a simple HERO section with image background and loop video.
- Toggle theme with Tailwind and CSS
- Toggle theme with Tailwind and Next.js
Toggle Theme#
Init a new tailwind project
npm install -D tailwindcssnpx tailwindcss init
Below is the project structure
|--src|--toggle-theme.html|--input.css|--masthead.m4v|--masthead-poster.jpg|--dist|--output.css|--package.json|--run.sh|--tailwind.config.js
This is the content of package.json
{"devDependencies": {"tailwindcss": "^3.3.2"}}
The command to compile tailwind css
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
First update the tailwind.config.js with darkMode: class
module.exports = {darkMode: "class",content: ["./src/**/*.{html,js}"],theme: {extend: {},},plugins: [],}
then follow docs to setup javascript to togglet theme
localStorage.theme = "dark";document.getElementById("button").addEventListener("click", () => {if (document.getElementById("sun").classList.contains("hidden")) {document.getElementById("sun").classList.remove("hidden");document.getElementById("moon").classList.add("hidden");} else {document.getElementById("moon").classList.remove("hidden");document.getElementById("sun").classList.add("hidden");}if (localStorage.theme === "dark") {localStorage.theme = "light";document.documentElement.classList.remove("dark");document.documentElement.classList.add("light");} else {localStorage.theme = "dark";document.documentElement.classList.remove("light");document.documentElement.classList.add("dark");}});
Use some button icons (moon and sun) from Heroicons
<body><div class="min-h-screen dark:bg-slate-800"><h1 class="dark:text-white">Hello</h1><buttonclass="bg-orange-400 rounded-3xl p-2 w-14 cursor-pointer"id="button"><svgxmlns="http://www.w3.org/2000/svg"fill="none"viewBox="0 0 24 24"stroke-width="1.5"stroke="currentColor"id="sun"><pathstroke-linecap="round"stroke-linejoin="round"d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"/></svg><svgxmlns="http://www.w3.org/2000/svg"fill="none"viewBox="0 0 24 24"strokeWidth="{1.5}"stroke="currentColor"className="w-6 h-6"id="moon"class="hidden"><pathstrokeLinecap="round"strokeLinejoin="round"d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z"/></svg></button><script>{toggle script there}</script></div>
Togge Theme Next.js#
Create a new Next.js project
npx create-app-next@latest .
Project structure
|--app|--global.css|--layout.tsx|--page.tsx|--components|--header.tsx|--public|--next.config.js|--package.json|--tailwind.config.js
Similarly, update the tailwind.config.js with darkMode:class
module.exports = {darkMode: "class",content: ["./src/**/*.{html,js}"],theme: {extend: {},},plugins: [],}
Then create a simple Toggle theme button, actually it wrapped in to a Header component
"use client";import { useEffect, useState } from "react";import { IoSunny, IoMoon } from "react-icons/io5/index.js";const themes = ["light", "dark"];export const Header = () => {const [theme, setTheme] = useState(() => {// theme from local storageif (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {return localStorage.getItem("theme");}// theme from preferesif (typeof window !== "undefined" &&window.matchMedia("(prefers-color-scheme: dark)").matches) {return "dark";}return "light";});useEffect(() => {if (theme === "light") {document.documentElement.classList.remove("dark");} else {document.documentElement.classList.add("dark");}}, [theme]);return (<div className="bg-slate-200 dark:bg-slate-900 dark:text-white"><div className="max-w-3xl mx-auto flex flex-row justify-between items-center px-3 py-3"><h2 className="font-semibold tracking-tighter font-mplus text-lg">Takuya Matsuyama</h2>{MAGIC TOGGLE BUTTON}</div></div>);};
Please take note the magic toggle button
<div className="inline-flex items-center p-[3px] rounded-3xl bg-orange-300 dark:bg-zinc-600">{themes.map((t) => {const checked = t === theme;return (<buttonclassName={`${checked ? "bg-white text-black" : ""} cursor-pointer rounded-3xl p-2`}onClick={() => {console.log("change Theme");const t = theme === "light" ? "dark" : "light";localStorage.setItem("theme", t);setTheme(t);}}>{t === "light" ? <IoSunny /> : <IoMoon />}</button>);})}</div>
Finally, we can use the Header component in the root layout (layout.tsx)
import "./globals.css";import { Inter } from "next/font/google";import { Header } from "@/components/header";const inter = Inter({ subsets: ["latin"] });export const metadata = {title: "Create Next App",description: "Generated by create next app",};export default function RootLayout({children,}: {children: React.ReactNode;}) {return (<html lang="en" className="dark"><body className={inter.className}><Header></Header>{children}</body></html>);}