{"id":26910956,"url":"https://github.com/designcise/next-theme-toggle","last_synced_at":"2025-04-01T14:26:08.291Z","repository":{"id":209202595,"uuid":"723453860","full_name":"designcise/next-theme-toggle","owner":"designcise","description":"A simple theme toggle for Next.js 13+","archived":false,"fork":false,"pushed_at":"2024-01-30T20:42:21.000Z","size":534,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-26T14:43:43.809Z","etag":null,"topics":["client-components","dark-mode","dark-theme","darkmode","darkmodetoggle","nextjs","nextjs13","nextjs14","react","reactjs","server-components","typescript"],"latest_commit_sha":null,"homepage":"https://www.designcise.com/web/tutorial/how-to-create-non-flickering-dark-or-light-mode-toggle-in-next-js-using-localstorage","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/designcise.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-11-25T18:05:56.000Z","updated_at":"2024-02-03T02:21:44.000Z","dependencies_parsed_at":"2023-12-12T00:50:22.148Z","dependency_job_id":"3727eb5a-1d38-4f1b-9f46-00f17e6c9369","html_url":"https://github.com/designcise/next-theme-toggle","commit_stats":null,"previous_names":["designcise/next-theme-toggle"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/designcise%2Fnext-theme-toggle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/designcise%2Fnext-theme-toggle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/designcise%2Fnext-theme-toggle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/designcise%2Fnext-theme-toggle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/designcise","download_url":"https://codeload.github.com/designcise/next-theme-toggle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246653119,"owners_count":20812250,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client-components","dark-mode","dark-theme","darkmode","darkmodetoggle","nextjs","nextjs13","nextjs14","react","reactjs","server-components","typescript"],"created_at":"2025-04-01T14:26:07.728Z","updated_at":"2025-04-01T14:26:08.284Z","avatar_url":"https://github.com/designcise.png","language":"TypeScript","readme":"# next-theme-toggle\n\nA simple theme toggle for Next.js 13+ that allows switching between light and dark themes. Using this package would result in the following `class` and `style` attributes added to the `\u003chtml\u003e` element:\n\n```html\n\u003chtml class=\"dark\" style=\"color-scheme:dark\"\u003e\n  \u003c!-- ... --\u003e\n\u003c/html\u003e\n```\n\nYou can then [use different CSS selectors to create styles for dark/light themes](https://www.designcise.com/web/tutorial/how-to-create-non-flickering-dark-or-light-mode-toggle-in-next-js-using-localstorage#adding-the-ability-to-switch-themes).\n\n## Features\n\n- Easy implementation with just _two_ lines of code\n- TypeScript Support\n- Types are automatically loaded, whenever applicable\n- No flicker on page load\n- Toggle between `light`, `dark` and `auto` modes\n- Automatically choose color based on `prefers-color-scheme` when in \"`auto`\" mode\n- Update color when `prefers-color-scheme` changes in `auto` mode\n- Switch to opposite color when toggling from \"`auto`\"\n- Data is stored in `localStorage`\n- No unnecessary bloat\n- Well-tested\n\n## Installation\n\n### Prerequisites\n\n- Next.js 13+\n- React 18+\n\n### npm\n\n```shell\n$ npm install @designcise/next-theme-toggle\n```\n\n### yarn\n\n```shell\n$ yarn add @designcise/next-theme-toggle\n```\n\n## Quickstart\n\n\u003e **NOTE**: Please note that this approach relies on using `localStorage` on the client side to store theme information.\n\nAt a bare minimum you need to do the following:\n\n1. In your Next.js application's root layout file (typically, `app/layout.js`), do the following:\n\n```jsx\n// app/layout.js\nimport { ThemeProvider } from '@designcise/next-theme-toggle';\nimport { themes } from '@designcise/next-theme-toggle/server';\n\nexport default async function RootLayout() {\n  // 1: wrap components with `ThemeProvider` to pass theme props down to all components\n  // 2: optionally pass `storageKey` and `defaultTheme` to `ThemeProvider`\n  return (\n    \u003chtml\u003e\n      \u003cbody\u003e\n        \u003cThemeProvider storageKey=\"user-pref\" defaultTheme={themes.dark.type}\u003e\n          {children}\n        \u003c/ThemeProvider\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  )\n}\n```\n\nWith this setup, the `ThemeProvider` component will automatically inject an inline script into DOM that takes care of avoiding flicker on initial page load.\n\n\u003e **NOTE**: If you don't specify a `storageKey` or `defaultTheme` prop on `ThemeProvider`, default value will be used for `storageKey` while absence of `defaultTheme` would mean that the theme is automatically determined based on `prefers-color-scheme`. \n\n2. Create a button to toggle between light and dark theme:\n\n```jsx\n// components/ToggleThemeButton/index.jsx\n'use client'\n\nimport React, { useContext } from 'react'\nimport { useTheme } from '@designcise/next-theme-toggle'\n\nexport default function ToggleThemeButton() {\n  const { toggleTheme } = useTheme()\n\n  return \u003cbutton onClick={toggleTheme}\u003eToggle Theme\u003c/button\u003e\n}\n```\n\nYou can also do this manually by using `theme`, `themes`, and `setTheme()`, for example, like so:\n\n```jsx\n// components/ToggleThemeButton/index.jsx\n'use client'\n\nimport React, { useContext } from 'react'\nimport { useTheme } from '@designcise/next-theme-toggle'\n\nexport default function ToggleThemeButton() {\n  const { theme, themes, setTheme } = useTheme()\n\n  return (\n    \u003cbutton onClick={() =\u003e setTheme(theme.type === themes.dark.type ? themes.light : themes.dark)}\u003e\n      Toggle Theme\n    \u003c/button\u003e\n  )\n}\n```\n\n3. Add toggle button to your page(s):\n\n```jsx\n// app/page.js\nimport ToggleThemeButton from '@/components/ToggleThemeButton'\n\nexport default async function Home() {\n  return (\n    \u003cmain\u003e\n      \u003ch1\u003eHello World\u003c/h1\u003e\n\n      \u003cToggleThemeButton /\u003e\n    \u003c/main\u003e\n  )\n}\n```\n\n4. Add styling for dark and light themes:\n\n```css\n/* globals.css */\n:root body {\n  background: white;\n}\n\n:root.dark body {\n  background: black;\n}\n```\n\nor:\n\n```css\n/* globals.css */\nbody {\n  background: white;\n}\n\n.dark body {\n  background: black;\n}\n```\n\nor:\n\n```css\n/* globals.css */\nbody {\n  background: white;\n}\n\n@media (prefers-color-scheme: dark) {\n  body {\n    background: black;\n  }\n}\n```\n\nThat's it! You should have light/dark theme toggle in your Next.js application.\n\n## API\n\n### `ThemeProvider`\n\nYou can pass the following props to `ThemeProvider`:\n\n| Prop           |                     Type                     |                                       Description                                       |\n|----------------|:--------------------------------------------:|:---------------------------------------------------------------------------------------:|\n| `children`     | `React.ReactChild`\u0026vert;`React.ReactChild[]` |              Components to which the theme is passed down to via context.               |\n| `storageKey`   |                    String                    | Name of the key used for storage. Defaults to `DEFAULT_STORAGE_KEY` in `env.helper.ts`. |\n| `defaultTheme` |                    String                    | Default theme (`'light'`, `'dark'` or `auto`) to use on page load. Defaults to `auto`.  |\n\n### `useTheme()`\n\nThe `useTheme()` hook does not take any params; it returns the following:\n\n| Return Value  |   Type   |                                                             Description                                                              |\n|---------------|:--------:|:------------------------------------------------------------------------------------------------------------------------------------:|\n| `theme`       |  Object  |                                     The active theme (e.g. `{ type: 'light', color: 'light' }`).                                     |\n| `themes`      |  Object  |                     Allowed themes (e.g. `{ light: { type: 'light', color: 'light' }, dark: ..., auto: ... }`).                      |\n| `setTheme`    | Function |                                                       Setter to set new theme.                                                       |\n| `toggleTheme` | Function | Toggles the theme between `light` and `dark`. When toggling from `auto`, the opposite color to active color is automatically chosen. |\n\n### `themes`\n\nAn object, with the following properties:\n\n| Property |  Type  |                      Value                       |                         Description                         |\n|----------|:------:|:------------------------------------------------:|:-----------------------------------------------------------:|\n| `light`  | Object |       `{ type: 'light', color: 'light' }`        |                        Light theme.                         |\n| `dark`   | Object |        `{ type: 'dark', color: 'dark' }`         |                         Dark theme.                         |\n| `auto`   | Object | `{ type: 'auto', color: 'dark' \u0026vert; 'light' }` | Auto-determine theme color based on `prefers-color-scheme`. |\n\n\u003e **NOTE**: The `themes` object can be used in both, client components and server components.\n\nFor server components you can import `themes` like so:\n\n```jsx\nimport { themes } from '@designcise/next-theme-toggle/server'\n```\n\nFor client components, you can import it like so:\n\n```jsx\nimport { themes } from '@designcise/next-theme-toggle'\n```\n\n## Testing\n\nTests are written using React Testing Library and Jest. You can run the tests using the following command:\n\n### npm\n\n```shell\n$ npm test\n```\n\n### yarn\n\n```shell\n$ yarn test\n```\n\n## Issues\n\n### Reporting\n\n- File issues at https://github.com/designcise/next-theme-toggle/issues\n- Issue patches to https://github.com/designcise/next-theme-toggle/pulls\n\n### Troubleshooting Common Issues\n\n#### `Warning: Extra attributes from the server: class,style` in Console\n\nYou can safely ignore this warning as it _only_ shows on dev build and _not_ in the production build. This happens because the injected inline script adds _additional_ `class` and `style` attributes to the `html` element which _do not_ originally exist on the server-side generated page, leading to a _mismatch_ in the server-side and client-side rendered page.\n\n## Contributing\n\nhttps://github.com/designcise/next-theme-toggle/blob/main/CONTRIBUTING.md\n\n## License\n\nhttps://github.com/designcise/next-theme-toggle/blob/main/LICENSE.md\n\n## Resources\n\n- [How to Create Non-Flickering Dark/Light Mode Toggle in Next.js Using `localStorage`?](https://www.designcise.com/web/tutorial/how-to-create-non-flickering-dark-or-light-mode-toggle-in-next-js-using-localstorage)\n- [How to Create Non-Flickering Dark/Light Mode Toggle in Next.js Using Cookies?](https://www.designcise.com/web/tutorial/how-to-create-non-flickering-dark-or-light-mode-toggle-in-next-js-using-cookies)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdesigncise%2Fnext-theme-toggle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdesigncise%2Fnext-theme-toggle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdesigncise%2Fnext-theme-toggle/lists"}