diff --git a/lib/README.md b/lib/README.md index 501188d0..9db6887c 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,26 +1,52 @@ -# Nextjs Themes +# Next.js Themes -[![test](https://github.com/react18-tools/nextjs-themes/actions/workflows/test.yml/badge.svg)](https://github.com/react18-tools/nextjs-themes/actions/workflows/test.yml) [![Maintainability](https://api.codeclimate.com/v1/badges/aa896ec14c570f3bb274/maintainability)](https://codeclimate.com/github/react18-tools/nextjs-themes/maintainability) [![codecov](https://codecov.io/gh/react18-tools/nextjs-themes/graph/badge.svg)](https://codecov.io/gh/react18-tools/nextjs-themes) [![Version](https://img.shields.io/npm/v/nextjs-themes.svg?colorB=green)](https://www.npmjs.com/package/nextjs-themes) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/d18m/nextjs-themes.svg)](https://www.npmjs.com/package/nextjs-themes) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/nextjs-themes) [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/from-referrer/) +[![test](https://github.com/react18-tools/nextjs-themes/actions/workflows/test.yml/badge.svg)](https://github.com/react18-tools/nextjs-themes/actions/workflows/test.yml) [![Maintainability](https://api.codeclimate.com/v1/badges/149263e95a1388369bb9/maintainability)](https://codeclimate.com/github/react18-tools/nextjs-themes/maintainability) [![codecov](https://codecov.io/gh/react18-tools/nextjs-themes/branch/main/graph/badge.svg?token=SUTY0GHPHV)](https://codecov.io/gh/react18-tools/nextjs-themes) [![Version](https://img.shields.io/npm/v/nextjs-themes.svg?colorB=green)](https://www.npmjs.com/package/nextjs-themes) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/d18m/nextjs-themes.svg)](https://www.npmjs.com/package/nextjs-themes) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/nextjs-themes) [![Contact me on Codementor](https://www.codementor.io/m-badges/mayank1513/get-help.svg)](https://www.codementor.io/@mayank1513?refer=badge) -Nextjs Themes is a comprehensive library designed to unlock the full potential of React 18 server components. It provides customizable loading animation components and a fullscreen loader container, seamlessly integrating with React and Next.js. +
+Version 3 Short Notes: +Version 3.0 brings minor API changes along with major performance improvements and fixes. We have minimized changes to existing APIs. -βœ… Fully Treeshakable (import from `nextjs-themes/client/loader-container`) +Note: [react18-themes](https://github.com/react18-tools/react18-themes/) will now be maintained as `nextjs-themes`, as server-specific APIs are no longer needed. -βœ… Fully TypeScript Supported +
-βœ… Leverages the power of React 18 Server components +🀟 πŸ‘‰ [Unleash the Power of React Server Components](https://medium.com/javascript-in-plain-english/unleash-the-power-of-react-server-components-eb3fe7201231) -βœ… Compatible with all React 18 build systems/tools/frameworks +- βœ… Perfect dark mode in 2 lines of code +- βœ… Fully Treeshakable (`import from nextjs-themes/client/component`) +- βœ… Full TypeScript Support +- βœ… Unleash the full power of React 18 Server components -βœ… Documented with [Typedoc](https://react18-tools.github.io/nextjs-themes) ([Docs](https://react18-tools.github.io/nextjs-themes)) +> Exampand following to see more features. -βœ… Examples for Next.js, Vite, and Remix +
+

Motivation and Key Features:

-> Please consider starring [this repository](https://github.com/react18-tools/nextjs-themes) and sharing it with your friends. +This project was inspired by next-themes. Unlike next-themes, `nextjs-themes` doesn't require wrapping everything in a provider, allowing you to take full advantage of React 18 Server Components. Additionally, it offers more features and control over your app's theming. -## Getting Started +- βœ… Perfect dark mode in 2 lines of code +- βœ… Fully Treeshakable (`import from nextjs-themes/client/component`) +- βœ… Designed for excellence +- βœ… Full TypeScript Support +- βœ… Unleash the full power of React 18 Server components +- βœ… System setting with prefers-color-scheme +- βœ… Themed browser UI with color-scheme +- βœ… Support for Next.js 13 & Next.js 14 `appDir` +- βœ… No flash on load (for all - SSG, SSR, ISG, Server Components) +- βœ… Sync theme across tabs and windows +- βœ… Disable flashing when changing themes +- βœ… Force pages to specific themes +- βœ… Class and data attribute selector +- βœ… Manipulate theme via `useTheme` hook +- βœ… Documented with [Typedoc](https://react18-tools.github.io/nextjs-themes) ([Docs](https://react18-tools.github.io/nextjs-themes)) +- βœ… Use combinations of [data-th=""] and [data-color-scheme=""] for dark/light variants of themes +- βœ… Use [data-csp=""] to style based on colorSchemePreference. +
-### Installation +> Check out the [live example](https://nextjs-themes.vercel.app/). + +
+

Installation

```bash $ pnpm add nextjs-themes @@ -38,7 +64,14 @@ $ npm install nextjs-themes $ yarn add nextjs-themes ``` -## Want Lite Version? [![npm bundle size](https://img.shields.io/bundlephobia/minzip/nextjs-themes-lite)](https://www.npmjs.com/package/nextjs-themes-lite) [![Version](https://img.shields.io/npm/v/nextjs-themes-lite.svg?colorB=green)](https://www.npmjs.com/package/nextjs-themes-lite) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/d18m/nextjs-themes-lite.svg)](https://www.npmjs.com/package/nextjs-themes-lite) +
+ +
+

Want Lite Version?

+ +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/nextjs-themes-lite)](https://www.npmjs.com/package/nextjs-themes-lite) [![Version](https://img.shields.io/npm/v/nextjs-themes-lite.svg?colorB=green)](https://www.npmjs.com/package/nextjs-themes-lite) [![Downloads](https://img.jsdelivr.com/img.shields.io/npm/d18m/nextjs-themes-lite.svg)](https://www.npmjs.com/package/nextjs-themes-lite) + +
```bash $ pnpm add nextjs-themes-lite @@ -56,74 +89,270 @@ $ npm install nextjs-themes-lite $ yarn add nextjs-themes-lite ``` -> You need `r18gs` as a peer-dependency +> Note: `r18gs` is a peer dependency -### Import Styles +
-You can import styles globally or within specific components. +## Usage -```css -/* globals.css */ -@import "nextjs-themes/dist"; +### SPA (e.g., Vite, CRA) and Next.js pages directory (No server components) + +To add dark mode support, modify `_app.js` as follows: + +```js +import { ThemeSwitcher } from "nextjs-themes"; + +function MyApp({ Component, pageProps }) { + return ( + <> + + + + ); +} + +export default MyApp; ``` +βš‘πŸŽ‰Boom! Dark mode is ready in just a couple of lines! + +### With Next.js `app` router (Server Components) + +Update `app/layout.jsx` to add `ThemeSwitcher` from `nextjs-themes`: + ```tsx -// layout.tsx -import "nextjs-themes/dist/index.css"; +// app/layout.jsx +import { ThemeSwitcher } from "nextjs-themes"; + +export default function Layout({ children }) { + return ( + + + + + {children} + + + ); +} ``` -For selective imports: +Woohoo! Multiple theme modes with Server Components support! + +### HTML & CSS + +Next.js app supports dark mode, including System preference with `prefers-color-scheme`. The theme is synced between tabs, modifying the `data-theme` attribute on the `html` element: ```css -/* globals.css */ -@import "nextjs-themes/dist/client"; /** required if you are using LoaderContainer */ -@import "nextjs-themes/dist/server/bars/bars1"; +:root { + --background: white; + --foreground: black; +} + +[data-theme="dark"] { + --background: black; + --foreground: white; +} ``` -### Usage +## Images -Using loaders is straightforward. +Show different images based on the current theme: -```tsx -import { Bars1 } from "nextjs-themes/dist/server/bars/bars1"; +```jsx +import Image from "next/image"; +import { useTheme } from "nextjs-themes"; -export default function MyComponent() { - return someCondition ? : <>Something else...; +function ThemedImage() { + const { resolvedTheme } = useTheme(); + const src = resolvedTheme === "light" ? "/light.png" : "/dark.png"; + return ; } + +export default ThemedImage; ``` -For detailed API and options, refer to [the API documentation](https://react18-tools.github.io/nextjs-themes). +### useTheme + +The `useTheme` hook provides theme information and allows changing the theme: + +```js +import { useTheme } from "nextjs-themes"; -**Using LoaderContainer** +const ThemeChanger = () => { + const { theme, setTheme } = useTheme(); + + return ( +
+ The current theme is: {theme} + + +
+ ); +}; +``` -`LoaderContainer` is a fullscreen component. You can add this component directly in your layout and then use `useLoader` hook to toggle its visibility. +The `useTheme` hook returns the following object: ```tsx -// layout.tsx - - ... +interface UseThemeYield { + theme: string; + darkTheme: string; + lightTheme: string; + colorSchemePref: ColorSchemeType; + systemColorScheme: ResolvedColorSchemeType; + resolvedColorScheme: ResolvedColorSchemeType; + resolvedTheme: string; + setTheme: (theme: string) => void; + setDarkTheme: (darkTheme: string) => void; + setLightTheme: (lightTheme: string) => void; + setThemeSet: (themeSet: { darkTheme: string; lightTheme: string }) => void; + setColorSchemePref: (colorSchemePref: ColorSchemeType) => void; + toggleColorScheme: (skipSystem?: boolean) => void; + setForcedTheme: (forcedTheme: string) => void; + setForcedColorScheme: (forcedColorScheme: ColorSchemeType) => void; +} +``` + +
+

Force per page theme and color-scheme

+ +### Next.js App Router + +```tsx +import { ForceTheme } from "nextjs-themes"; + +function MyPage() { + return ( + <> + + ... + + ); +} + +export default MyPage; +``` + +### Next.js Pages Router + +For the pages router, you have two options. The first option is the same as the app router, and the second option, which is compatible with `next-themes`, involves adding the `theme` property to your page component like this: + +```javascript +function MyPage() { + return <>...; +} + +MyPage.theme = "my-theme"; + +export default MyPage; +``` + +Similarly, you can force a color scheme. This will apply your `defaultDark` or `defaultLight` theme, which can be configured via hooks. + +
+ +### With Styled Components and any CSS-in-JS + +Next Themes works with any library. For Styled Components, `createGlobalStyle` in your custom App: + +```js +// pages/_app.js +import { createGlobalStyle } from "styled-components"; +import { ThemeSwitcher } from "nextjs-themes"; + +const GlobalStyle = createGlobalStyle` + :root { + --fg: #000; + --bg: #fff; + } + + [data-theme="dark"] { + --fg: #fff; + --bg: #000; + } +`; + +function MyApp({ Component, pageProps }) { + return ( + <> + + + + + ); +} +``` + +### With Tailwind + +In `tailwind.config.js`, set the dark mode property to class: + +```js +// tailwind.config.js +module.exports = { + darkMode: "class", +}; ``` +βš‘πŸŽ‰Ready to use dark mode in Tailwind! + +> Caution: Your class must be `"dark"`, which is the default value used in this library. Tailwind requires the class name `"dark"` for dark-theme. + +Use dark-mode specific classes: + ```tsx -// some other page or component -import { useLoader } from "nextjs-themes/dist/hooks"; - -export default MyComponent() { - const { setLoading } = useLoader(); - useCallback(()=>{ - setLoading(true); - ...do some work - setLoading(false); - }, []) - ... +

+``` + +## Migration + +> Refer to the [migration guide](./guides/migration.md). + +## Docs + +[Typedoc](https://react18-tools.github.io/nextjs-themes) + +### 🀩 Don't forget to star this repo! + +Want a hands-on course for getting started with Turborepo? Check out [React and Next.js with TypeScript](https://www.udemy.com/course/react-and-next-js-with-typescript/?referralCode=7202184A1E57C3DCA8B2) + +## FAQ + +**Do I need to use CSS variables with this library?** + +No. You can hard code values for every class: + +```css +.my-class { + color: #555; +} + +[data-theme="dark"] .my-class { + color: white; } ``` +**Why is `resolvedTheme` and `resolvedColorScheme` necessary?** + +To reflect the System theme preference and forced theme/colorScheme pages in your UI. For instance, buttons or dropdowns indicating the current colorScheme should say "system" when the System colorScheme preference is active. + +`resolvedTheme` is useful for modifying behavior or styles at runtime: + +```js +const { resolvedTheme, resolvedColorScheme } = useTheme(); +const background = getBackground(resolvedTheme); + +
+``` + +Without `resolvedTheme`, you would only know the theme is "system", not what it resolved to. + ## License This library is licensed under the MPL-2.0 open-source license. -> Please consider enrolling in [our courses](https://mayank-chaudhari.vercel.app/courses) or [sponsoring](https://github.com/sponsors/mayank1513) our work. +> Please consider enrolling in [our courses](https://mayank-chaudhari.vercel.app/courses) or [sponsoring](https://github.com/sponsors/mayank1513) our work.