I wanted to allow users to change the theme of the application by picking which theme they want the body’s background color changes and all button colors. But the problem is that whenever I use document.querySelectorAll(‘.btn-theme-1’).style.backgroundColor it tells me that it cannot read those properties.
I know of useRef() but in my case I am trying to select all buttons throughout the entire application. Not just one element in the current component. So I would like to know if there is a way to fix what I am attempting or if I am doing this the wrong way.
Here is the code for what I tried. This is my pick theme component:
import ColorThemes from '../data/ColorThemes';
import { useEffect } from 'react';
const PickTheme = () => {
const changeTheme = (c) => {
document.body.style.background = c.default || c.bgColor;
document.body.style.color = c.bodyColor;
document.querySelector('.bi-quote').style.color = c.buttonBg;
document.querySelectorAll('.text-color').forEach(el => el.style.color = c.fontColor)
document.querySelectorAll('.btn-theme-1').forEach(el => {
el.style.color = c.buttonColor;
el.style.backgroundColor = c.buttonBg;
});
};
useEffect(() => {
},[changeTheme]);
return(
ColorThemes.background.map(c => {
if(c.bgColor) {
return(
<button type="button" key={c.bgColor} className="btn btn-light me-2 p-3 rounded-5" onClick={() => changeTheme(c)} style={{backgroundColor: c.bgColor}}></button>
);
} else {
return(
<><br/><button type="button" key={c.default} className="btn btn-light me-2 mt-2 rounded-5" onClick={() => changeTheme(c)}>Default</button></>
);
}
})
);
};
export default PickTheme;
It successfully changes the bodys color and background color but not the other classes. I tried with and without useEffect and still receive the same issue.
If I comment out everything except the last selector, the buttons then change colors. So maybe it is conflicting or cannot change everything at once, for example:
const changeTheme = (c) => {
// document.body.style.background = c.default || c.bgColor;
// document.body.style.color = c.bodyColor;
// document.querySelector('.bi-quote').style.color = c.buttonBg;
// document.querySelectorAll('.text-color').forEach(el => el.style.color = c.fontColor)
document.querySelectorAll('.btn-theme-1').forEach(el => {
el.style.color = c.buttonColor;
el.style.backgroundColor = c.buttonBg;
});
};
This changes the buttons background and color after commenting out the other parts.
>Solution :
I know of useRef() but in my case I am trying to select all buttons throughout the entire application. Not just one element in the current component.
Using .querySelector or any other selector will select only those elements that are currently rendered, actually. So if you e.g. toggle the state and component re-renders with different elements, they will not be affected with your change, which will result in partially toggled theme for different elements.
You should either set a context, wrapping whole App or set a redux variable holding info which theme is currently selected. Then, you will be able to manipulate styles using e.g. theme in styled components: https://styled-components.com/docs/advanced#theming or just toggling classNames with css modules, basing on that variable.