{"id":13476373,"url":"https://github.com/saadeghi/theme-change","last_synced_at":"2025-04-12T21:18:50.402Z","repository":{"id":40689506,"uuid":"258491101","full_name":"saadeghi/theme-change","owner":"saadeghi","description":"Change CSS theme with toggle, buttons or select using CSS custom properties and localStorage","archived":false,"fork":false,"pushed_at":"2024-02-19T05:40:34.000Z","size":100,"stargazers_count":1565,"open_issues_count":12,"forks_count":49,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-05T20:00:32.496Z","etag":null,"topics":["css-custom-properties","css-theme","css-variables","javascript","localstorage","theme","theming"],"latest_commit_sha":null,"homepage":"https://codepen.io/saadeghi/pen/OJypbNM","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/saadeghi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"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},"funding":{"custom":"https://donate.lol/bitcoin:bc1qz9xhu04sf7r3chngc5ezts5yd60mc6hatugrly"}},"created_at":"2020-04-24T11:17:37.000Z","updated_at":"2025-04-04T06:50:53.000Z","dependencies_parsed_at":"2024-01-13T18:31:04.456Z","dependency_job_id":"f5b2fcb1-5d0d-4bb2-811a-70ab4ed9424f","html_url":"https://github.com/saadeghi/theme-change","commit_stats":{"total_commits":96,"total_committers":12,"mean_commits":8.0,"dds":0.15625,"last_synced_commit":"3ea64ec41c702c1787365b59a3c400cb890ec569"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saadeghi%2Ftheme-change","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saadeghi%2Ftheme-change/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saadeghi%2Ftheme-change/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saadeghi%2Ftheme-change/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saadeghi","download_url":"https://codeload.github.com/saadeghi/theme-change/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248631798,"owners_count":21136569,"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":["css-custom-properties","css-theme","css-variables","javascript","localstorage","theme","theming"],"created_at":"2024-07-31T16:01:29.518Z","updated_at":"2025-04-12T21:18:50.383Z","avatar_url":"https://github.com/saadeghi.png","language":"JavaScript","readme":"# 🎨 CSS Theme Change\n\n- A tiny JS script to handle CSS themes\n- Change CSS theme using `button`, `toggle` or a `\u003cselect\u003e`\n- It saves chosen theme in browser and uses it again when page reloads\n\n[![][build]][build-url] [![][install-size]][install-size-url] [![][js]][js-url]  \n[![][npm]][npm-url] [![][dl]][npm-url] [![][commit]][gh-url]\n\n# 🖥 Demo\n\n- See example code on [codepen](https://codepen.io/saadeghi/pen/OJypbNM)\n- See Sample site on [Netlify](https://css-theme-changer.netlify.app/)\n- See Vue Example on [Vercel](https://vue-3-theme.vercel.app)\n\n[![image](https://user-images.githubusercontent.com/7342023/80218042-e3c67e00-8655-11ea-94e8-925d0dcbfd57.gif)](#)\n\n# 💿 Use\n\n## JS\n\nUse CDN:\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/theme-change@2.0.2/index.js\"\u003e\u003c/script\u003e\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  Or use NPM: \n\u003c/summary\u003e\n\nInstall: `npm i theme-change --save` and use it in your js file:\n\n```js\nimport { themeChange } from 'theme-change'\nthemeChange()\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n  or if it's a React project: \n\u003c/summary\u003e\n\nInstall: `npm i theme-change --save` and use it in your js file:\n\n```js\nimport { useEffect } from 'react'\nimport { themeChange } from 'theme-change'\n\nuseEffect(() =\u003e {\n  themeChange(false)\n  // 👆 false parameter is required for react project\n}, [])\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n  or if it's a Vue 3 project (using composition API): \n\u003c/summary\u003e\n\nInstall: `npm i theme-change --save` and use it in your js file:\n\n```js\nimport { onMounted } from 'vue'\nimport { themeChange } from 'theme-change'\n\nexport default {\n  setup() {\n    onMounted(() =\u003e {\n      themeChange(false)\n    })\n  },\n}\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n  or if it's a Vue 2 project (using options API): \n\u003c/summary\u003e\n\nInstall: `npm i theme-change --save` and use it in your js file:\n\n```js\nimport { themeChange } from 'theme-change'\n\nexport default {\n  mounted: function () {\n    themeChange(false)\n  },\n}\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n  or if it's a Svelte project: \n\u003c/summary\u003e\n\nInstall: `npm i theme-change --save` and use it in your svelte component that uses one theme-change attributes:\n\n```js\nimport { onMount } from 'svelte'\nimport { themeChange } from 'theme-change'\n\n// NOTE: the element that is using one of the theme attributes must be in the DOM on mount\nonMount(() =\u003e {\n  themeChange(false)\n  // 👆 false parameter is required for svelte\n})\n```\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n  or if it's a SolidJS project: \n\u003c/summary\u003e\n\nInstall: `npm i theme-change --save` and use it in your js/jsx/tsx file:\n\n```js\nimport { onMount } from 'solid-js'\nimport { themeChange } from 'theme-change'\nonMount(async () =\u003e {\n  themeChange();\n})\n```\n\n\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n  or if it's a Astro project: \n\u003c/summary\u003e\n\nInstall: `npm i theme-change --save` and use it in your .astro file(s):\n\nAstro is a bit tricky because of how is rendering html page as a MPA (Multiple Pages Application)\nAstro projects are therefore subject to [FART](https://css-tricks.com/flash-of-inaccurate-color-theme-fart/) problem. To prevent this we will use the [is:inline](https://docs.astro.build/en/reference/directives-reference/#isinline) astro directive.\n\nIf you want to apply themes on a single [astro page](https://docs.astro.build/en/core-concepts/astro-pages/) (remember Astro is an MPA framework) :\n\n`src/pages/mypage.astro`\n\n```js\n---\n---\n\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n  \u003cscript is:inline\u003e\n      // ☝️ This script prevent the FART effect.\n      if (localStorage.getItem(\"theme\") === null) {\n        document.documentElement.setAttribute(\"data-theme\", \"light\");\n      } else\n      document.documentElement.setAttribute(\"data-theme\",localStorage.getItem(\"theme\"));\n      // \"theme\" LocalStorage value is set by the package to remember user preference.\n      // The value is checked and applyed before rendering anything.\n  \u003c/script\u003e\n  \u003cscript\u003e\n      import { themeChange } from \"theme-change\";\n      themeChange();\n       // 👆 you could import the CDN directly instead of these two lines\n    \u003c/script\u003e\n    \u003ctitle\u003eMy crazy credit page\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003ch1\u003eWelcome to my credit page!\u003c/h1\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\nIf you want to apply themes to all your [astro pages](https://docs.astro.build/en/core-concepts/astro-pages/), you need to execute both scripts in a Astro [layout](https://docs.astro.build/en/core-concepts/layouts/#sample-layout), it would need to wrap all your astro pages like so:\n\n`src/layouts/MyCrazyLayout.astro`\n\n```html\n---\n---\n\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003cscript is:inline\u003e\n      // ☝️ This script prevent the FART effect.\n      if (localStorage.getItem(\"theme\") === null) {\n        document.documentElement.setAttribute(\"data-theme\", \"light\");\n      } else\n        document.documentElement.setAttribute(\n          \"data-theme\",\n          localStorage.getItem(\"theme\")\n        );\n      // \"theme\" LocalStorage value is set by the package to remember user preference.\n      // The value is checked and applyed before rendering anything.\n    \u003c/script\u003e\n    \u003cscript\u003e\n      import { themeChange } from 'theme-change';\n      themeChange();\n      // 👆 you could import the CDN directly instead of these two lines\n    \u003c/script\u003e\n    \u003cmeta charset=\"utf-8\" /\u003e\n    \u003ctitle\u003eMy Cool Astro Layout Wraping All My Pages\u003c/title\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cnav\u003e\n      \u003ca href=\"#\"\u003eHome\u003c/a\u003e\n      \u003ca href=\"#\"\u003ePosts\u003c/a\u003e\n      \u003ca href=\"#\"\u003eContact\u003c/a\u003e\n    \u003c/nav\u003e\n    \u003carticle\u003e\n      \u003cslot /\u003e\n      \u003c!-- your content from src/pages/index.astro is injected here --\u003e\n    \u003c/article\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n`src/pages/index.astro`\n\n```js\n---\nimport MyCrazyLayout from '../layouts/MyCrazyLayout.astro';\n---\n\u003cMySiteLayout\u003e\n  \u003cp\u003eMy page content, wrapped in a layout!\u003c/p\u003e\n\u003c/MySiteLayout\u003e\n```\n\n\u003c/details\u003e\n\n## CSS\n\nSet your themeable style as custom properties in CSS like this:\n\n```css\n:root {\n  --my-color: #fff;\n  /* or any other variables/style */\n}\n[data-theme='dark'] {\n  --my-color: #000;\n}\n[data-theme='pink'] {\n  --my-color: #ffabc8;\n}\n```\n\nthen use your variables on any element\n\n```css\nbody {\n  background-color: var(--my-color);\n}\n```\n\n## HTML\n\nThere are 3 options:\n\n- ### Using buttons to set a theme\n\n  [![btn](https://user-images.githubusercontent.com/7342023/101527827-c0adcc00-39a3-11eb-9e41-24bfa91ea96c.gif)](#)\n\n  Clicking on these buttons, sets the chosen theme and also adds the `ACTIVECLASS` to the chosen button\n\n  ```\n  \u003cbutton data-set-theme=\"\" data-act-class=\"ACTIVECLASS\"\u003e\u003c/button\u003e\n  \u003cbutton data-set-theme=\"dark\" data-act-class=\"ACTIVECLASS\"\u003e\u003c/button\u003e\n  \u003cbutton data-set-theme=\"pink\" data-act-class=\"ACTIVECLASS\"\u003e\u003c/button\u003e\n  ```\n\n- ### Toggle between two themes\n\n  [![toggle](https://user-images.githubusercontent.com/7342023/101527821-bf7c9f00-39a3-11eb-822b-7751265a18a5.gif)](#)\n\n  Clicking on this element, toggles between `dark` and `light` theme and also adds the `ACTIVECLASS` to the element\n\n  ```\n  \u003cbutton data-toggle-theme=\"dark,light\" data-act-class=\"ACTIVECLASS\"\u003e\u003c/button\u003e\n  ```\n\n- ### `\u003cselect\u003e` menu\n\n  [![select](https://user-images.githubusercontent.com/7342023/101527790-b4297380-39a3-11eb-9173-bc909549d160.gif)](#)\n\n  ```\n  \u003cselect data-choose-theme\u003e\n    \u003coption value=\"\"\u003eDefault\u003c/option\u003e\n    \u003coption value=\"dark\"\u003eDark\u003c/option\u003e\n    \u003coption value=\"pink\"\u003ePink\u003c/option\u003e\n  \u003c/select\u003e\n  ```\n\n# Advance use\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  Set theme based on OS color-scheme\n\u003c/summary\u003e\n\n```css\n@media (prefers-color-scheme: dark){\n  :root{\n    --my-color: #252b30;\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  Use with PurgeCSS\n\u003c/summary\u003e\n\nIf you're using [Purge CSS](https://purgecss.com/), you might need to [safe list](https://purgecss.com/safelisting.html#in-the-css-directly) your CSS using the comments below because your secondary themes will be purged\n\n- Safelist `[data-theme]` on postcss config\n\n  ```js\n  module.exports = {\n    purge: {\n      options: {\n        safelist: [/data-theme$/],\n      },\n    },\n  }\n  ```\n\n- Safelist inside CSS file\n\n  ```css\n  /*! purgecss start ignore */\n\n  [data-theme='dark'] {\n    --my-color: #252b30;\n  }\n\n  /*! purgecss end ignore */\n  ```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n  Using custom localStorage key\n\u003c/summary\u003e\n\nIf you want to use a custom localStorage key, you can add it to the `data-key` attribute like this:\n\n```html\n\u003cselect data-choose-theme data-key=\"admin-panel\"\u003e\n\n\u003cbutton data-key=\"front-page\" data-set-theme=\"\"\u003e\n\n\u003cspan data-key=\"premium-user-theme\" data-toggle-theme=\"dark\"\u003e\n```\n\n\u003c/details\u003e\n\n---\n\n[install-size]: https://badgen.net/bundlephobia/minzip/theme-change?label=bundle%20size\u0026color=purple\n[js]: https://badgen.net/badgesize/normal/https/unpkg.com/theme-change/index.js?label=file%20size\u0026color=purple\n[npm]: https://badgen.net/npm/v/theme-change?label=version\u0026color=purple\n[dl]: https://badgen.net/npm/dt/theme-change?icon=npm\u0026color=purple\n[commit]: https://badgen.net/github/last-commit/saadeghi/theme-change?icon=github\u0026color=purple\n[build]: https://badgen.net/github/checks/saadeghi/theme-change?label=build\n[build-url]: https://github.com/saadeghi/theme-change/actions\n[install-size-url]: https://bundlephobia.com/result?p=theme-change\n[js-url]: https://unpkg.com/theme-change@latest/index.js\n[npm-url]: https://www.npmjs.com/package/theme-change\n[gh-url]: https://github.com/saadeghi/theme-change\n","funding_links":["https://donate.lol/bitcoin:bc1qz9xhu04sf7r3chngc5ezts5yd60mc6hatugrly"],"categories":["JavaScript","theme"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaadeghi%2Ftheme-change","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaadeghi%2Ftheme-change","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaadeghi%2Ftheme-change/lists"}