{"id":14990123,"url":"https://github.com/googlechromelabs/dark-mode-toggle","last_synced_at":"2025-05-14T03:11:19.559Z","repository":{"id":34932720,"uuid":"191904180","full_name":"GoogleChromeLabs/dark-mode-toggle","owner":"GoogleChromeLabs","description":"A custom element that allows you to easily put a Dark Mode 🌒 toggle or switch on your site:","archived":false,"fork":false,"pushed_at":"2025-05-07T16:57:01.000Z","size":1613,"stargazers_count":1195,"open_issues_count":1,"forks_count":72,"subscribers_count":17,"default_branch":"main","last_synced_at":"2025-05-07T17:45:46.672Z","etag":null,"topics":["custom-elements","custom-elements-v1","dark-mode","dark-mode-switcher","dark-mode-toggle","dark-theme","dark-theme-switcher","dark-theme-toggle","media-queries","prefers-color-scheme","supported-color","web-components"],"latest_commit_sha":null,"homepage":"https://googlechromelabs.github.io/dark-mode-toggle/demo/index.html","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GoogleChromeLabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-06-14T08:17:48.000Z","updated_at":"2025-05-07T16:53:54.000Z","dependencies_parsed_at":"2023-01-15T10:40:45.477Z","dependency_job_id":"9be294e8-d651-4401-a297-3fca03b2a83a","html_url":"https://github.com/GoogleChromeLabs/dark-mode-toggle","commit_stats":{"total_commits":158,"total_committers":15,"mean_commits":"10.533333333333333","dds":0.379746835443038,"last_synced_commit":"2878a35de5abcdc6b831221a45c94f9c7075c1e5"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleChromeLabs%2Fdark-mode-toggle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleChromeLabs%2Fdark-mode-toggle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleChromeLabs%2Fdark-mode-toggle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GoogleChromeLabs%2Fdark-mode-toggle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GoogleChromeLabs","download_url":"https://codeload.github.com/GoogleChromeLabs/dark-mode-toggle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254059518,"owners_count":22007771,"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":["custom-elements","custom-elements-v1","dark-mode","dark-mode-switcher","dark-mode-toggle","dark-theme","dark-theme-switcher","dark-theme-toggle","media-queries","prefers-color-scheme","supported-color","web-components"],"created_at":"2024-09-24T14:19:30.295Z","updated_at":"2025-05-14T03:11:14.541Z","avatar_url":"https://github.com/GoogleChromeLabs.png","language":"JavaScript","readme":"# `\u003cdark-mode-toggle\u003e` Element\n\n[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/dark-mode-toggle)\n\nA custom element that allows you to easily put a _Dark Mode 🌒_ toggle or switch\non your site, so you can initially adhere to your users' preferences according\nto\n[`prefers-color-scheme`](https://drafts.csswg.org/mediaqueries-5/#prefers-color-scheme),\nbut also allow them to (optionally permanently) override their system setting\nfor just your site.\n\n📚 Read all(!) about dark mode in the related article\n[Hello Darkness, My Old Friend](https://web.dev/prefers-color-scheme/).\n\n## Installation\n\nInstall from npm:\n\n```bash\nnpm install --save dark-mode-toggle\n```\n\nOr, alternatively, use a `\u003cscript type=\"module\"\u003e` tag (served from unpkg's CDN):\n\n```html\n\u003cscript type=\"module\" src=\"https://unpkg.com/dark-mode-toggle\"\u003e\u003c/script\u003e\n```\n\n![Dark mode toggle live coding sample.](https://user-images.githubusercontent.com/145676/94532333-0466b580-023e-11eb-947e-f73044a7cd63.gif)\n\n(See the [original HD version](https://youtu.be/qfsvoPhx-bE) so you can pause.)\n\n## Usage\n\nThere are two ways how you can use `\u003cdark-mode-toggle\u003e`:\n\n### ① Using different stylesheets per color scheme that are conditionally loaded\n\nThe custom element assumes that you have organized your CSS in different files\nthat you load conditionally based on the **`media`** attribute in the\nstylesheet's corresponding `link` element. This is a great performance pattern,\nas you don't force people to download CSS that they don't need based on their\ncurrent theme preference, yet non-matching stylesheets still get loaded, but\ndon't compete for bandwidth in the critical rendering path. You can also have\nmore than one file per theme. The example below illustrates the principle.\n\n\u003c!--\n```\n\u003ccustom-element-demo\u003e\n  \u003ctemplate\u003e\n    \u003clink rel=\"stylesheet\" href=\"https://googlechromelabs.github.io/dark-mode-toggle/demo/common.css\"\u003e\n    \u003clink rel=\"stylesheet\" href=\"https://googlechromelabs.github.io/dark-mode-toggle/demo/light.css\" media=\"(prefers-color-scheme: light)\"\u003e\n    \u003clink rel=\"stylesheet\" href=\"https://googlechromelabs.github.io/dark-mode-toggle/demo/dark.css\" media=\"(prefers-color-scheme: dark)\"\u003e\n    \u003cscript type=\"module\" src=\"https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs\"\u003e\u003c/script\u003e\n    \u003cstyle\u003e\n      #dark-mode-toggle-1 {\n        --dark-mode-toggle-dark-icon: url(\"https://googlechromelabs.github.io/dark-mode-toggle/demo/moon.png\");\n        --dark-mode-toggle-light-icon: url(\"https://googlechromelabs.github.io/dark-mode-toggle/demo/sun.png\");\n        --dark-mode-toggle-remember-icon-checked: url(\"https://googlechromelabs.github.io/dark-mode-toggle/demo/checked.svg\");\n        --dark-mode-toggle-remember-icon-unchecked: url(\"https://googlechromelabs.github.io/dark-mode-toggle/demo/unchecked.svg\");\n        --dark-mode-toggle-remember-font: 0.75rem 'Helvetica';\n        --dark-mode-toggle-legend-font: bold 0.85rem 'Helvetica';\n        --dark-mode-toggle-label-font: 0.85rem 'Helvetica';\n        --dark-mode-toggle-color: var(--text-color);\n        --dark-mode-toggle-background-color: none;\n        --dark-mode-toggle-active-mode-background-color: var(--accent-color);\n        --dark-mode-toggle-remember-filter: invert(100%);\n      }\n    \u003c/style\u003e\n    \u003cnext-code-block\u003e\u003c/next-code-block\u003e\n  \u003c/template\u003e\n\u003c/custom-element-demo\u003e\n```\n--\u003e\n\n```html\n\u003chead\u003e\n  \u003clink rel=\"stylesheet\" href=\"common.css\" /\u003e\n  \u003clink\n    rel=\"stylesheet\"\n    href=\"light.css\"\n    media=\"(prefers-color-scheme: light)\"\n  /\u003e\n  \u003clink rel=\"stylesheet\" href=\"dark.css\" media=\"(prefers-color-scheme: dark)\" /\u003e\n  \u003cscript\n    type=\"module\"\n    src=\"https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs\"\n  \u003e\u003c/script\u003e\n\u003c/head\u003e\n\u003c!-- ... --\u003e\n\u003cmain\u003e\n  \u003ch1\u003eHi there\u003c/h1\u003e\n  \u003cimg\n    src=\"https://googlechromelabs.github.io/dark-mode-toggle/demo/cat.jpg\"\n    alt=\"Sitting cat in front of a tree\"\n    width=\"320\"\n    height=\"195\"\n  /\u003e\n  \u003cp\u003eCheck out the dark mode toggle in the upper right corner!\u003c/p\u003e\n\u003c/main\u003e\n\u003caside\u003e\n  \u003cdark-mode-toggle\n    id=\"dark-mode-toggle-1\"\n    legend=\"Theme Switcher\"\n    appearance=\"switch\"\n    dark=\"Dark\"\n    light=\"Light\"\n    remember=\"Remember this\"\n  \u003e\u003c/dark-mode-toggle\u003e\n\u003c/aside\u003e\n```\n\nThe above method might cause flashing\n([#77](https://github.com/GoogleChromeLabs/dark-mode-toggle/issues/77)) when the\npage loads, as the dark mode toggle module is loaded after the page is rendered.\nA loader script can be used to apply the saved theme before the page is\nrendered. Wrap the stylesheet tags with\n`\u003cnoscript id=\"dark-mode-toggle-stylesheets\"\u003e...\u003c/noscript\u003e` and add the loader\nscript as follows:\n\n```html\n\u003chead\u003e\n  \u003clink rel=\"stylesheet\" href=\"common.css\" /\u003e\n  \u003cnoscript id=\"dark-mode-toggle-stylesheets\"\u003e\n    \u003clink\n      rel=\"stylesheet\"\n      href=\"light.css\"\n      media=\"(prefers-color-scheme: light)\"\n    /\u003e\n    \u003clink\n      rel=\"stylesheet\"\n      href=\"dark.css\"\n      media=\"(prefers-color-scheme: dark)\"\n    /\u003e\n    \u003cmeta name=\"color-scheme\" content=\"dark light\" /\u003e\n  \u003c/noscript\u003e\n  \u003cscript src=\"https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle-stylesheets-loader.js\"\u003e\u003c/script\u003e\n  \u003cscript\n    type=\"module\"\n    src=\"https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs\"\n  \u003e\u003c/script\u003e\n\u003c/head\u003e\n\u003c!-- ... --\u003e\n```\n\n### ② Using a CSS class that you toggle\n\nIf you prefer to not split your CSS in different files based on the color\nscheme, you can instead work with a class that you toggle, for example\n`class=\"dark\"`. You can see this in action in\n[this demo](https://dark-mode-class-toggle.glitch.me/).\n\n```js\nimport * as DarkModeToggle from 'https://googlechromelabs.github.io/dark-mode-toggle/src/dark-mode-toggle.mjs';\n\nconst toggle = document.querySelector('dark-mode-toggle');\nconst body = document.body;\n\n// Set or remove the `dark` class the first time.\ntoggle.mode === 'dark'\n  ? body.classList.add('dark')\n  : body.classList.remove('dark');\n\n// Listen for toggle changes (which includes `prefers-color-scheme` changes)\n// and toggle the `dark` class accordingly.\ntoggle.addEventListener('colorschemechange', () =\u003e {\n  body.classList.toggle('dark', toggle.mode === 'dark');\n});\n```\n\n## Demo\n\nSee the custom element in action in the\n[interactive demo](https://googlechromelabs.github.io/dark-mode-toggle/demo/index.html).\nIt shows four different kinds of synchronized `\u003cdark-mode-toggle\u003e`s. If you use\nChrome on an Android device, pay attention to the address bar's theme color, and\nalso note how the favicon changes.\n\n\u003cimg src=\"https://user-images.githubusercontent.com/145676/59537453-ec5b0d80-8ef6-11e9-9efb-c44ed9db24b6.png\" width=\"400\" alt=\"Dark\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/145676/59537454-ec5b0d80-8ef6-11e9-8a89-5e3fbda9c15c.png\" width=\"400\" alt=\"Light\"\u003e\n\n## Properties\n\nProperties can be set directly on the custom element at creation time, or\ndynamically via JavaScript.\n\n👉 Note that the dark and light **icons** are set via CSS variables, see\n[Style Customization](#style-customization) below.\n\n| Name         | Required | Values                          | Default                                                                                                                                                            | Description                                                                                                                                            |\n| ------------ | -------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `mode`       | No       | Any of `\"dark\"` or `\"light\"`    | Defaults to whatever the user's preferred color scheme is according to `prefers-color-scheme`, or `\"light\"` if the user's browser doesn't support the media query. | If set overrides the user's preferred color scheme.                                                                                                    |\n| `appearance` | No       | Any of `\"toggle\"` or `\"switch\"` | Defaults to `\"toggle\"`.                                                                                                                                            | The `\"switch\"` appearance conveys the idea of a theme switcher (light/dark), whereas `\"toggle\"` conveys the idea of a dark mode toggle (on/off).       |\n| `permanent`  | No       | `true` if present               | Defaults to not remember the last choice.                                                                                                                          | If present remembers the last selected mode (`\"dark\"` or `\"light\"`), which allows the user to permanently override their usual preferred color scheme. |\n| `legend`     | No       | Any string                      | Defaults to no legend.                                                                                                                                             | Any string value that represents the legend for the toggle or switch.                                                                                  |\n| `light`      | No       | Any string                      | Defaults to no label.                                                                                                                                              | Any string value that represents the label for the `\"light\"` mode.                                                                                     |\n| `dark`       | No       | Any string                      | Defaults to no label.                                                                                                                                              | Any string value that represents the label for the `\"dark\"` mode.                                                                                      |\n| `remember`   | No       | Any string                      | Defaults to no label.                                                                                                                                              | Any string value that represents the label for the \"remember the last selected mode\" functionality.                                                    |\n\n## Events\n\n- `colorschemechange`: Fired when the color scheme gets changed.\n- `permanentcolorscheme`: Fired when the color scheme should be permanently\n  remembered or not.\n\n## Complete Example\n\nInteracting with the custom element:\n\n```js\n/* On the page */\nconst darkModeToggle = document.querySelector('dark-mode-toggle');\n\n// Set the mode to dark\ndarkModeToggle.mode = 'dark';\n// Set the mode to light\ndarkModeToggle.mode = 'light';\n\n// Set the legend to \"Dark Mode\"\ndarkModeToggle.legend = 'Dark Mode';\n// Set the light label to \"off\"\ndarkModeToggle.light = 'off';\n// Set the dark label to \"on\"\ndarkModeToggle.dark = 'on';\n\n// Set the appearance to resemble a switch (theme: light/dark)\ndarkModeToggle.appearance = 'switch';\n// Set the appearance to resemble a toggle (dark mode: on/off)\ndarkModeToggle.appearance = 'toggle';\n\n// Set a \"remember the last selected mode\" label\ndarkModeToggle.remember = 'Remember this';\n\n// Remember the user's last color scheme choice\ndarkModeToggle.setAttribute('permanent', '');\n// Forget the user's last color scheme choice\ndarkModeToggle.removeAttribute('permanent');\n```\n\nReacting on color scheme changes:\n\n```js\n/* On the page */\ndocument.addEventListener('colorschemechange', (e) =\u003e {\n  console.log(`Color scheme changed to ${e.detail.colorScheme}.`);\n});\n```\n\nReacting on \"remember the last selected mode\" functionality changes:\n\n```js\n/* On the page */\ndocument.addEventListener('permanentcolorscheme', (e) =\u003e {\n  console.log(\n    `${e.detail.permanent ? 'R' : 'Not r'}emembering the last selected mode.`,\n  );\n});\n```\n\n## Style Customization\n\nYou can style the custom element with\n[`::part()`](https://developer.mozilla.org/en-US/docs/Web/CSS/::part). See the\ndemo's\n[CSS source code](https://github.com/GoogleChromeLabs/dark-mode-toggle/blob/master/demo/common.css)\nfor some concrete examples. The exposed parts and their names can be seen below:\n\n```html\n\u003cform part=\"form\"\u003e\n  \u003cfieldset part=\"fieldset\"\u003e\n    \u003clegend part=\"legend\"\u003e\u003c/legend\u003e\n    \u003cinput part=\"lightRadio\" id=\"l\" name=\"mode\" type=\"radio\" /\u003e\n    \u003clabel part=\"lightLabel\" for=\"l\"\u003e\u003c/label\u003e\n    \u003cinput part=\"darkRadio\" id=\"d\" name=\"mode\" type=\"radio\" /\u003e\n    \u003clabel part=\"darkLabel\" for=\"d\"\u003e\u003c/label\u003e\n    \u003cinput part=\"toggleCheckbox\" id=\"t\" type=\"checkbox\" /\u003e\n    \u003clabel part=\"toggleLabel\" for=\"t\"\u003e\u003c/label\u003e\n    \u003caside part=\"aside\"\u003e\n      \u003cinput part=\"permanentCheckbox\" id=\"p\" type=\"checkbox\" /\u003e\n      \u003clabel part=\"permanentLabel\" for=\"p\"\u003e\u003c/label\u003e\n    \u003c/aside\u003e\n  \u003c/fieldset\u003e\n\u003c/form\u003e\n```\n\nAdditionally, you can use a number of exposed CSS variables, as listed in the\nfollowing:\n\n| CSS Variable Name                                 | Default                                | Description                                                                                                                                                              |\n| ------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `--dark-mode-toggle-light-icon`                   | No icon                                | The icon for the light state in `background-image:` notation.                                                                                                            |\n| `--dark-mode-toggle-dark-icon`                    | No icon                                | The icon for the dark state in `background-image:` notation.                                                                                                             |\n| `--dark-mode-toggle-icon-size`                    | 1rem                                   | The icon size in CSS length data type notation.                                                                                                                          |\n| `--dark-mode-toggle-remember-icon-checked`        | No icon                                | The icon for the checked \"remember the last selected mode\" functionality in `background-image:` notation.                                                                |\n| `--dark-mode-toggle-remember-icon-unchecked`      | No icon                                | The icon for the unchecked \"remember the last selected mode\" functionality in `background-image:` notation.                                                              |\n| `--dark-mode-toggle-color`                        | User-Agent stylesheet text color       | The main text color in `color:` notation.                                                                                                                                |\n| `--dark-mode-toggle-background-color`             | User-Agent stylesheet background color | The main background color in `background-color:` notation.                                                                                                               |\n| `--dark-mode-toggle-legend-font`                  | User-Agent `\u003clegend\u003e` font             | The font of the legend in shorthand `font:` notation.                                                                                                                    |\n| `--dark-mode-toggle-label-font`                   | User-Agent `\u003clabel\u003e` font              | The font of the labels in shorthand `font:` notation.                                                                                                                    |\n| `--dark-mode-toggle-remember-font`                | User-Agent `\u003clabel\u003e` font              | The font of the \"remember the last selected mode\" functionality label in shorthand `font:` notation.                                                                     |\n| `--dark-mode-toggle-icon-filter`                  | No filter                              | The filter for the dark icon (so you can use all black or all white icons and just invert one of them) in `filter:` notation.                                            |\n| `--dark-mode-toggle-remember-filter`              | No filter                              | The filter for the \"remember the last selected mode\" functionality icon (so you can use all black or all white icons and just invert one of them) in `filter:` notation. |\n| `--dark-mode-toggle-active-mode-background-color` | No background color                    | The background color for the currently active mode in `background-color:` notation.                                                                                      |\n\n## Hacking on `\u003cdark-mode-toggle\u003e`\n\nThe core custom element code lives in\n[`src/dark-mode-toggle.mjs`](https://github.com/GoogleChromeLabs/dark-mode-toggle/blob/master/src/dark-mode-toggle.mjs).\nYou can start hacking and testing your changes by running `npm run start` and\nthen navigating to \u003chttp://localhost:8080/demo/\u003e. No build step required 🎉,\nthis happens automatically upon `npm publish`ing. If for whatever reason you\nwant to build locally, run `npm run build`. You can lint by running\n`npm run lint`.\n\nThe HTML and the CSS used by `\u003cdark-mode-toggle\u003e` is hard-coded as a template\nliteral in the file `src/dark-mode-toggle.mjs`. For optimal performance, the\ncontents of this literal are hand-minified. If you need to tweak the HTML or the\nCSS, find the unminified template literal contents in\n`src/template-contents.tpl` and copy them over to `src/dark-mode-toggle.mjs`.\nOnce your changes are done, commit them to both the `*.tpl` file (in unminified\nform) and the `*.mjs` file (in minified form).\n\n(This is actually just making a strong argument for\n[CSS Modules](https://github.com/w3c/webcomponents/issues/759) and\n[HTML Modules](https://github.com/w3c/webcomponents/issues/645) that would allow\nfor proper tools integration).\n\n## Proudly used on…\n\n- [**v8.dev**](https://v8.dev/): V8 is Google’s open source high-performance\n  JavaScript and WebAssembly engine, written in C++.\n\n  ![v8.dev in light mode](https://user-images.githubusercontent.com/145676/66128744-c913b580-e5ee-11e9-8c44-e2ca1d24dacb.png)\n\n  ![v8.dev in dark mode](https://user-images.githubusercontent.com/145676/66128803-ea74a180-e5ee-11e9-8792-c411a54346fc.png)\n\n- Your site here…\n\n## Notes\n\nThis is not an official Google product.\n\n## Acknowledgements\n\nThanks to all\n[contributors](https://github.com/GoogleChromeLabs/dark-mode-toggle/graphs/contributors)\nfor making `\u003cdark-mode-toggle\u003e` even better! Usage video by\n[Tomek Sułkowski](https://twitter.com/sulco).\n\n## License\n\nCopyright 2019 Google LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nthis file except in compliance with the License. You may obtain a copy of the\nLicense at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgooglechromelabs%2Fdark-mode-toggle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgooglechromelabs%2Fdark-mode-toggle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgooglechromelabs%2Fdark-mode-toggle/lists"}