DEV Community

Nabilla Trisnani
Nabilla Trisnani

Posted on

Step 1: Setup Frontend

This step is going to be a short one, but let’s go!

Install NextJS:

  1. Use this command
pnpm create next-app@latest my-app
Enter fullscreen mode Exit fullscreen mode
  1. Choose Yes for everything

Setup Theme Switcher

For this project, I’m going to add theme switcher feature. Which is why I’m going to change the global.css to this:

@import url("https://fonts.googleapis.com/css2?family=Funnel+Sans:ital,wght@0,300..800;1,300..800&display=swap");
@import "tailwindcss";

:root {
    --white: #fffffe;

    --light-background: #fffffe;
    --light-secondary-background: #d9d4e7;
    --light-text-primary: #0e172c;
    --light-text-secondary: #fffffe;
    --light-highlight: #a786df;

    --dark-background: #232946;
    --dark-secondary-background: #d4d8f0;
    --dark-text-primary: #b8c1ec;
    --dark-text-secondary: #232946;
    --dark-highlight: #eebbc3;
}

@theme inline {
    --color-white: var(--white);

    --color-light-background: var(--light-background);
    --color-light-secondary-background: var(--light-secondary-background);
    --color-light-text-primary: var(--light-text-primary);
    --color-light-text-secondary: var(--light-text-secondary);
    --color-light-highlight: var(--light-highlight);

    --color-dark-background: var(--dark-background);
    --color-dark-secondary-background: var(--dark-secondary-background);
    --color-dark-text-primary: var(--dark-text-primary);
    --color-dark-text-secondary: var(--dark-text-secondary);
    --color-dark-highlight: var(--dark-highlight);
}

@custom-variant dark (&:where(.dark, .dark *));

body {
    font-family: "Funnel Sans", sans-serif;
}

Enter fullscreen mode Exit fullscreen mode

The, add next-themes by run this command:

npm install next-themes
Enter fullscreen mode Exit fullscreen mode

and for the layout.tsx, change to this:

import type { Metadata } from "next";
import "./globals.css";
import { ThemeProvider } from "next-themes";

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider attribute="class" defaultTheme="system">
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

Enter fullscreen mode Exit fullscreen mode

After that, change the page.tsx to this:

"use client";

import { useTheme } from "next-themes";
import { useEffect, useState } from "react";

export default function Home() {
  const [mounted, setMounted] = useState(false);
  const { setTheme } = useTheme();

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) {
    return null;
  }

  return (
    <div className="flex min-h-screen items-center justify-center bg-light-background dark:bg-dark-background">
      <div className="flex gap-2 p-1 border border-[3px] border-[#010101] dark:border-[#72757e] rounded-[3px]">
        <button
          onClick={() => setTheme("light")}
          className="text-[#fffffe] dark:text-[#fffffe] bg-[#7f5af0] dark:bg-transparent transition-colors duration-300 p-1 border border-[#7f5af0] dark:border-transparent rounded-[3px]"
        >
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-5">
            <path d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-2.25A.75.75 0 0 1 12 18ZM7.758 17.303a.75.75 0 0 0-1.061-1.06l-1.591 1.59a.75.75 0 0 0 1.06 1.061l1.591-1.59ZM6 12a.75.75 0 0 1-.75.75H3a.75.75 0 0 1 0-1.5h2.25A.75.75 0 0 1 6 12ZM6.697 7.757a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 0 0-1.061 1.06l1.59 1.591Z" />
          </svg>
        </button>
        <button
          onClick={() => setTheme("dark")}
          className="text-[#181818] dark:text-[#fffffe] bg-white dark:bg-[#2cb67d] transition-colors duration-300 p-1 border border-transparent dark:border-[#2cb67d] rounded-[3px]"
        >
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="size-5">
            <path fillRule="evenodd" d="M9.528 1.718a.75.75 0 0 1 .162.819A8.97 8.97 0 0 0 9 6a9 9 0 0 0 9 9 8.97 8.97 0 0 0 3.463-.69.75.75 0 0 1 .981.98 10.503 10.503 0 0 1-9.694 6.46c-5.799 0-10.5-4.7-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 0 1 .818.162Z" clipRule="evenodd" />
          </svg>
        </button>
      </div>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Once everything is set, it should look like this:

A gif of a simple theme switcher

It needs to be said that the global.css might change in the future, so don’t forget to check my repo for updates.

Thanks for coming by and Peace ✌


Author

Top comments (0)