theme-change icon indicating copy to clipboard operation
theme-change copied to clipboard

Fixing toggle function

Open gabrieldesousah opened this issue 1 year ago • 5 comments

Hi, the themeToggle() function have some problems. It is creating a new eventlistener each time that the toggle is clicked and in vue isn't working (I'm trying with https://daisyui.com/)

This is a suggestion to fix (this code: https://github.com/saadeghi/theme-change/blob/master/src/toggle.js):

function themeToggle() {
  const toggleEl = document.querySelector("[data-toggle-theme]");
  const dataKey = toggleEl?.getAttribute("data-key") || "theme";
  const currentTheme = localStorage.getItem(dataKey);

  function setTheme(theme) {
    document.documentElement.setAttribute("data-theme", theme);
    document.querySelectorAll("[data-toggle-theme]").forEach((el) => {
      el.classList.toggle(el.getAttribute("data-act-class"), theme !== null);
    });
    if (theme === null) {
      localStorage.removeItem(dataKey);
    } else {
      localStorage.setItem(dataKey, theme);
    }
  }

  if (currentTheme) {
    setTheme(currentTheme);
  }

  if (toggleEl) {
    toggleEl.addEventListener("click", function () {
      const themesList = toggleEl.getAttribute("data-toggle-theme");
      if (themesList) {
        const themesArray = themesList.split(",");
        const currentThemeIndex = themesArray.indexOf(
          document.documentElement.getAttribute("data-theme")
        );
        const newThemeIndex = (currentThemeIndex + 1) % themesArray.length;
        setTheme(themesArray[newThemeIndex]);
      }
    });
  }
}

In vue, I make works with:

<template>
      <input ref="themeToggle" data-toggle-theme="light,dark" data-act-class="ACTIVECLASS" type="checkbox"
        class="toggle" />
</template>

<script setup lang='ts'>
import { onMounted, ref } from 'vue'
import { themeChange } from 'theme-change'

const themeToggle = ref(null);

const setTheme = (theme, dataKey) => {
  document.documentElement.setAttribute('data-theme', theme);
  document.querySelectorAll('[data-toggle-theme]').forEach((el) => {
    el.classList.toggle(el.getAttribute('data-act-class'), theme !== null);
  });
  if (theme === null) {
    localStorage.removeItem(dataKey);
  } else {
    localStorage.setItem(dataKey, theme);
  }
};

onMounted(() => {
  themeChange(false)
  const toggleEl = themeToggle.value;
  const dataKey = toggleEl.getAttribute('data-key') || 'theme';
  const currentTheme = localStorage.getItem(dataKey);

  if (currentTheme) {
    setTheme(currentTheme, dataKey);
  }

  toggleEl.addEventListener('click', () => {
    const themesList = toggleEl.getAttribute('data-toggle-theme');
    if (themesList) {
      const themesArray = themesList.split(',');
      const currentThemeIndex = themesArray.indexOf(
        document.documentElement.getAttribute('data-theme')
      );
      const newThemeIndex = (currentThemeIndex + 1) % themesArray.length;
      setTheme(themesArray[newThemeIndex], dataKey);
    }
  });
});
</script>

gabrieldesousah avatar Aug 11 '23 02:08 gabrieldesousah

I also have the issue in React. It works nicely just after set up, but when restarting the local server it fails to update the theme. Here's my code:

tailwind.config.js

module.exports = {
   content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    [...]
  },
  daisyui: {
    themes: [
      "dark",
      "light"      
    ],
  },
  plugins: [require("daisyui")],
}

index.html

<!DOCTYPE html>
<html lang="en" data-theme="light">

   [...]
</html>

Toggle Component

import { useEffect } from "react";
import { themeChange } from "theme-change";

const ThemeSwitch = () => {
    useEffect(() => {
      themeChange(false)      
    }, [])
    
  return (
    <div className="p-2">    
      <label className="swap swap-rotate">          
        <input type="checkbox" data-toggle-theme="light,dark"/>                
        <svg className="swap-on fill-current w-8 h-8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z"/></svg>        
        <svg className="swap-off fill-current w-8 h-8" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z"/></svg>        
      </label>    
    </div>
  );
};

export default ThemeSwitch;

Working with React 18

guschiavon avatar Oct 01 '23 18:10 guschiavon

I have the same problem that @guschiavon on react...

Djibdjib avatar Oct 20 '23 13:10 Djibdjib

Me too, I use next.js and facing the same issue :(

universeroc avatar Nov 26 '23 13:11 universeroc

Me too, with Next 14 and React 18

wutsqo avatar Dec 31 '23 04:12 wutsqo

Same issue, using Next, React, and DaisyUI

cph101 avatar Apr 07 '24 18:04 cph101