1.0.6 • Published 10 months ago

simple-nextjs-darkmode v1.0.6

Weekly downloads
-
License
MIT
Repository
github
Last release
10 months ago

simple-nextjs-darkmode

This package is targetted for Next.Js projects using shadcn/ui, but may work with other ui frameworks depending on their implementation.

Motivation

shadcn/ui handles dark mode by applying the dark class to some root element. I couldn't find a clean way to respect the user's system preference when using React Server Components, so I wrote this.

Features

  • Automatic system preference detection
  • Automatic live updates, no page reload required
  • Simple installation and usage
  • Stores preference per client in a cookie
    • Planned: Callbacks for persistent storage per user

Installation

npm install --save simple-nextjs-darkmode

Usage

The package provides a DEFAULT_CLASS_NAME constant (defaults to dark from shadcn/ui).

To override this, set the data-darkmode-class attribute to the class you want to use on the element tagged with data-darkmode-target.

<body data-darkmode-target data-darkmode-class="dark-theme"></body>

With React Server Components

React Server Components are the preferred way to use this package. Rendering dark mode on the server prevents a flash of light for dark mode users.

import { getServerDarkMode } from "simple-nextjs-darkmode/server";
import { DarkModeManager } from "simple-nextjs-darkmode/client";
import { DEFAULT_CLASS_NAME } from "simple-nextjs-darkmode/constants";

export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {
    const darkMode = getServerDarkMode(); // Use this to get the dark mode state for the initial server-side render

    return (
        <html lang="en">
            <body
                className={darkMode ? DEFAULT_CLASS_NAME : ""}
                data-darkmode-target
            >
                <DarkModeManager />
                {children}
            </body>
        </html>
    );
}

Without React Server Components

Without React Server Components, an additional flag is required to force the dark mode to be updated on the client. The user will see a flash of light mode for dark mode users. This is obviously less than ideal, but it works if you can't use Server Components for some reason.

"use client";

import {
    getClientDarkMode,
    DarkModeManager,
} from "simple-nextjs-darkmode/client";

export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {
    const darkMode = getClientDarkMode(); // Only necessary if you need to know the current dark mode state

    return (
        <html lang="en">
            <body data-darkmode-target>
                <DarkModeManager alwaysUpdate />
                {children}
            </body>
        </html>
    );
}

Updating the user preference

Allowing the user to change the dark mode preference is as simple as calling updateClientPreference with the new preference.

"use client";

import {
    getClientPreference,
    updateUserPreference,
} from "simple-nextjs-darkmode/client";

export default function UpdatePreference() {
    return (
        <div>
            <p>Current dark mode preference: {getClientPreference()}</p>
            <button onClick={() => updateClientPreference("dark")}>
                Dark Mode
            </button>
            <button onClick={() => updateClientPreference("light")}>
                Light Mode
            </button>
            <button onClick={() => updateClientPreference("system")}>
                System Preference
            </button>
            {children}
        </div>
    );
}

Issues

This is my first ever npm package, so I'm sure there's something I didn't do quite right. If you find any issues, please open an issue here or feel free to fix it yourself and submit a pull request.

Versioning

This package uses semver for versioning.

1.0.6

10 months ago

1.0.5

10 months ago

1.0.4

10 months ago

1.0.3

10 months ago

1.0.2

10 months ago

1.0.1

10 months ago

1.0.0

10 months ago