Tutorial Laravel 12 API Next JS 15 dan Tailwind CSS #4 Mengaktifkan Dark Mode dengan next-themes

Belajar membangun aplikasi fullstack modern dengan backend Laravel 12 RESTful API, frontend Next.js, dan desain menggunakan Tailwind CSS. Tutorial ini membahas step-by-step mulai dari setup environment, pembuatan API, konsumsi API di Next.js, hingga integrasi UI responsif.

✅ Telah dilihat 384 kali

Rating: 5.00 ⭐

... 13 August 2025, 20:33

Konfigurasi Tema

Supaya dashboard yang sudah kita pasang mendukung tema, baik dark maupun light mode, kita perlu melakukan sedikit konfigurasi terlebih dahulu. Langkah pertama adalah membuat sebuah component baru bernama theme-provider.tsx. Component ini nantinya akan bertanggung jawab untuk mengatur tema secara global di seluruh dashboard.

Untuk menempatkannya, silakan letakkan di dalam folder components. Maka struktur foldernya akan terlihat seperti ini:

components/
├── theme-provider.tsx
└── ...

Silakan buka file tersebut kemudian masukkan kode berikut ini:

"use client"

import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"

export function ThemeProvider({
  children,
  ...props
}: React.ComponentProps<typeof NextThemesProvider>) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
  1. "use client" Baris ini menandakan bahwa file ini adalah client component di Next.js 13+, artinya komponen ini akan dijalankan di browser, bukan di server. Ini penting karena pengaturan tema (dark/light) harus dilakukan di sisi client agar bisa merespons interaksi pengguna secara dinamis.

  2. Import React dan NextThemesProvider

    import * as React from "react"
    import { ThemeProvider as NextThemesProvider } from "next-themes"
    
    • React dibutuhkan karena kita menulis komponen React.
    • NextThemesProvider diimport dari package next-themes. Ini adalah provider utama yang akan mengatur tema aplikasi secara global. Kita ganti namanya menjadi NextThemesProvider supaya tidak bentrok dengan nama komponen kita sendiri.
  3. Membuat Komponen ThemeProvider

    export function ThemeProvider({ children, ...props }: React.ComponentProps<typeof NextThemesProvider>) { ... }
    
    • Kita membuat wrapper component bernama ThemeProvider.
    • Parameter children digunakan supaya semua komponen di dalamnya akan mendapatkan akses ke pengaturan tema.
    • ...props memungkinkan kita meneruskan semua properti yang diterima NextThemesProvider ke dalam wrapper ini (misal: defaultThemeattribute, dsb).
  4. Menggunakan NextThemesProvider

    return <NextThemesProvider {...props}>{children}</NextThemesProvider>
    
    • Di sini kita membungkus seluruh children dengan NextThemesProvider, sehingga semua komponen anak bisa mendapatkan state tema (dark/light) dan otomatis menyesuaikan tampilan.
    • Dengan cara ini, kita punya satu titik konfigurasi tema yang bisa digunakan di seluruh aplikasi.

Komponen ini adalah lapisan global yang membuat aplikasi Next.js kita bisa mendukung dark mode dan light mode dengan mudah. Kita cukup membungkus seluruh aplikasi dengan ThemeProvider ini, lalu semua komponen otomatis bisa merespons perubahan tema.


Toggle Switch

Langkah berikutnya adalah membuat sebuah file baru lagi dengan nama toggle.tsx didalam folder components. Maka struktur foldernya akan terlihat seperti ini:

components/
├── theme-provider.tsx
├── toggle.tsx
└── ...

Silakan buka file tersebut kemudian masukkan kode berikut ini:

"use client"

import * as React from "react"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"

import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"

export function ModeToggle() {
  const { setTheme } = useTheme()

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="outline" size="icon">
          <Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
          <Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
          <span className="sr-only">Toggle theme</span>
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end">
        <DropdownMenuItem onClick={() => setTheme("light")}>
          Light
        </DropdownMenuItem>
        <DropdownMenuItem onClick={() => setTheme("dark")}>
          Dark
        </DropdownMenuItem>
        <DropdownMenuItem onClick={() => setTheme("system")}>
          System
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

  1. "use client" Menandakan komponen ini dijalankan di client, karena pengaturan tema harus merespons interaksi pengguna secara real-time.
  2. Imports penting
    • useTheme dari next-themes untuk mengubah tema (dark/light/system).
    • Sun & Moon dari lucide-react sebagai ikon visual untuk tema.
    • Button dan DropdownMenu dari UI components untuk membuat tombol dan menu dropdown.
  3. Komponen ModeToggle
    • Menggunakan DropdownMenu untuk menampilkan pilihan tema.
    • Tombol menampilkan ikon Sun/Moon yang berubah sesuai mode saat ini (menggunakan class dark:).
    • DropdownMenuItem memanggil setTheme("light"|"dark"|"system") saat diklik, sehingga tema langsung berubah.

Konfigurasi Site Header

Silakan buka file site-header.tsx kemudian panggil ModeToggle yang sudah kita buat kedalam nav site header untuk menggantikan github. Sehingga akan menjadi seperti berikut ini:

"use client"
import { Separator } from "@/components/ui/separator"
import { SidebarTrigger } from "@/components/ui/sidebar"
import { ModeToggle } from "@/components/toggle"


export function SiteHeader() {
  return (
    <header className="flex h-(--header-height) shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)">
      <div className="flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6">
        <SidebarTrigger className="-ml-1" />
        <Separator
          orientation="vertical"
          className="mx-2 data-[orientation=vertical]:h-4"
        />
        <h1 className="text-base font-medium">Next.JS CRUD</h1>
        <div className="ml-auto flex items-center gap-2">
          <ModeToggle />
        </div>
      </div>
    </header>
  )
}


Konfigurasi Layout

Setelah kita membuat ThemeProvider, langkah selanjutnya adalah menghubungkannya ke layout utama aplikasi. Dengan begitu, semua halaman dan komponen di dalam dashboard akan otomatis mendukung dark dan light mode.

Caranya mudah: buka file layout.tsx yang terletak didalam folder app, lalu bungkus children dengan ThemeProvider yang sudah kita buat sebelumnya. Hasilnya akan terlihat seperti ini:

import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider"

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

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
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      ><ThemeProvider
        attribute="class"
        defaultTheme="system"
        enableSystem
        disableTransitionOnChange
      >
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}

<html suppressHydrationWarning> dipakai untuk menghindari peringatan React ketika tema (atau state lain yang berbeda antara server dan client) berubah saat halaman dihydrate, sambil tetap menjaga layout dan fungsi tema berjalan normal.

Preview

pada materi berikutnya, kita akan melanjutkan dengan konfigurasi Sidebar sesuai dengan kebutuhan aplikasi kita.

🔥 Flash Sale


📜 Table Of Contents


📌 Daftar Episode


Daftar eBook