Theme Toggle
Theme Toggle
Light / Dark mode toggle for Framer websites.
Let your visitors choose between light and dark mode using this theme toggle override for Framer.
The toggle works with the Framer built-in light/dark color system, making it easily integrable with new or existing projects.
All you have to do is:
Copy the code below (or remix the project).
Paste the code in a new code override in your project.
Apply it to any frame on your website.
And voilà! You know have a perfectly functioning toggle on your website.
import type { ComponentType } from "react"
import { addPropertyControls, ControlType } from "framer"
import React, { useEffect, useState } from "react"
function getOSTheme() {
if (typeof window !== "undefined" && typeof document !== "undefined") {
return window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
}
return "light"
}
function setInitialState() {
const osTheme = getOSTheme()
const currentToggleState =
localStorage.getItem("currentToggleState") ||
(osTheme === "dark" ? "dark" : "light")
localStorage.setItem("currentToggleState", currentToggleState)
if (typeof document !== "undefined") {
const styleTag = document.getElementsByTagName("style")[0]
const newCSS = styleTag.innerHTML.replace(
/prefers-color-scheme: \w+/,
`prefers-color-scheme: ${
(currentToggleState === "dark" && osTheme === "dark") ||
(currentToggleState === "light" && osTheme === "light")
? "dark"
: "light"
}`
)
styleTag.innerHTML = newCSS
}
return currentToggleState === "dark"
}
export function themeSwictherBasedOnSystem(Component): ComponentType {
return (props) => {
const [isOn, setIsOn] = useState(setInitialState())
const toggle = () => {
const newToggleState = !isOn ? "dark" : "light"
setIsOn(!isOn)
localStorage.setItem("currentToggleState", newToggleState)
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("themeChange"))
}
}
useEffect(() => {
if (typeof window !== "undefined") {
const mediaQuery = window.matchMedia(
"(prefers-color-scheme: dark)"
)
mediaQuery.addListener((e) => {
const newTheme = e.matches ? "dark" : "light"
localStorage.setItem("currentOsTheme", newTheme)
localStorage.setItem("currentToggleState", newTheme)
setIsOn(newTheme === "dark")
if (typeof document !== "undefined") {
const styleTag =
document.getElementsByTagName("style")[0]
const newCSS = styleTag.innerHTML.replace(
/prefers-color-scheme: \w+/,
`prefers-color-scheme: ${
(newTheme === "dark" && newTheme === "dark") ||
(newTheme === "light" && newTheme === "light")
? "dark"
: "light"
}`
)
styleTag.innerHTML = newCSS
}
window.dispatchEvent(new CustomEvent("themeChange"))
})
}
}, [])
useEffect(() => {
if (
typeof window !== "undefined" &&
typeof document !== "undefined"
) {
const currentToggleState = isOn ? "dark" : "light"
const currentOsTheme =
localStorage.getItem("currentOsTheme") || getOSTheme()
const styleTag = document.getElementsByTagName("style")[0]
const newCSS = styleTag.innerHTML.replace(
/prefers-color-scheme: \w+/,
`prefers-color-scheme: ${
(currentToggleState === "dark" &&
currentOsTheme === "dark") ||
(currentToggleState === "light" &&
currentOsTheme === "light")
? "dark"
: "light"
}`
)
styleTag.innerHTML = newCSS
localStorage.setItem("currentToggleState", currentToggleState)
}
}, [isOn])
const [isClient, setIsClient] = useState(false)
useEffect(() => {
setIsClient(true)
}, [])
return <Component {...props} onClick={toggle} />
}
}
Overview:
Light / Dark mode toggle for Framer websites.