Nouveaux cours Framer (+ 8 h)
Nouveaux cours Framer (+ 8 h)
Découvrir
Framer

Créer un switch dark/light

Javascript
HTML
CSS
Auteur
Aurélien Gallier
Démo lecture seule
Voir
Remix Link
Voir
Démo live
Voir

Copie-colle ce code React dans un nouveau composant Framer

Ajout ce code dans un nouvel élément de code "Create component".


import * as React from "react"
import { Frame, addPropertyControls, ControlType } from "framer"
import { Sun, Moon } from "lucide-react"

// Récupère le thème stocké
function getStoredTheme() {
    return localStorage.getItem("currentToggleState")
}

// Met à jour le CSS pour la préférence de thème
function updateTheme(theme: "light" | "dark") {
    if (typeof document !== "undefined") {
        const styleTag = document.getElementsByTagName("style")[0]
        const newCSS = styleTag.innerHTML.replace(
            /prefers-color-scheme: \w+/, 
            `prefers-color-scheme: ${theme}`
        )
        styleTag.innerHTML = newCSS
    }
    window.dispatchEvent(new CustomEvent("themeChange"))
}

export function ThemeSwitch({
    backgroundColor,
    iconColor,
    switchSize,
    circleColor,
    strokeWidth,
}: {
    backgroundColor: string
    iconColor: string
    switchSize: number
    circleColor: string
    strokeWidth: number
}) {
    const [isOn, setIsOn] = React.useState(false)
    const [isThemeSet, setIsThemeSet] = React.useState(false)

    // Bascule le thème et stocke l'état
    const toggle = () => {
        const newState = isOn ? "dark" : "light"
        setIsOn(!isOn)
        localStorage.setItem("currentToggleState", newState)
        updateTheme(newState)
    }

    // Initialisation au chargement
    React.useEffect(() => {
        const stored = getStoredTheme()
        if (stored === "light" || stored === "dark") {
            setIsOn(stored === "light")
            updateTheme(stored)
        } else {
            updateTheme("light")
        }
        setIsThemeSet(true)
    }, [])

    const circleSize = switchSize / 2 - switchSize / 8
    const circlePadding = switchSize / 16
    const iconSize = circleSize - circlePadding * 2

    return (
        <Frame
            width={switchSize}
            height={switchSize / 2}
            background={backgroundColor}
            style={{
                borderRadius: switchSize / 4,
                cursor: "pointer",
                position: "relative",
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                padding: `0 ${switchSize / 8}px`,
            }}
            onClick={toggle}
        >
            {isThemeSet && (
                <Frame
                    width={circleSize}
                    height={circleSize}
                    background={circleColor}
                    style={{
                        borderRadius: "50%",
                        position: "absolute",
                        left: isOn
                            ? `calc(100% - ${circleSize + circlePadding}px)`
                            : `${circlePadding}px`,
                        transition: "left 0.2s",
                        display: "flex",
                        alignItems: "center",
                        justifyContent: "center",
                        padding: circlePadding,
                    }}
                    initial={false}
                    animate={{
                        left: isOn
                            ? `calc(100% - ${circleSize + circlePadding}px)`
                            : `${circlePadding}px`,
                    }}
                >
                    {isOn ? (
                        <Sun size={iconSize} color={iconColor} strokeWidth={strokeWidth} />
                    ) : (
                        <Moon size={iconSize} color={iconColor} strokeWidth={strokeWidth} />
                    )}
                </Frame>
            )}
        </Frame>
    )
}

ThemeSwitch.defaultProps = {
    backgroundColor: "#e0e0e0",
    iconColor: "#000000",
    switchSize: 60,
    circleColor: "#ffffff",
    strokeWidth: 2,
}

addPropertyControls(ThemeSwitch, {
    backgroundColor: {
        title: "Background",
        type: ControlType.Color,
        defaultValue: "#e0e0e0",
    },
    switchSize: {
        title: "Size",
        type: ControlType.Number,
        defaultValue: 60,
        min: 20,
        max: 200,
        step: 1,
    },
    circleColor: {
        title: "Circle",
        type: ControlType.Color,
        defaultValue: "#ffffff",
    },
    iconColor: {
        title: "Icon",
        type: ControlType.Color,
        defaultValue: "#000000",
    },
    strokeWidth: {
        title: "Stroke",
        type: ControlType.Number,
        defaultValue: 2,
        min: 1,
        max: 5,
        step: 0.5,
    },
})
  

Tuto vidéo

Ajoute tes styles à ton projet Framer

Une fois ton switcher crée, tu dois ajouter créer des styles enregistrés dans Framer en veillant bien à ajouter une couleur en version light et une couleur en version dark.

Personnalise ton switcher dark/light

Le switcher a été conçu pour être entièrement personnalisé. Tu peux également créer des styles enregistrés pour lui donner une apparence en version light et une autre apparence en version dark.

Ajoute un bouton te permettant de passer de ton thème light à ton dark en un clic !

Envie d'aller plus loin ?
Je m'inscris