Reputation: 61
I am new to react. I am trying to change the entire theme of the website by using a switch that is inside a component called NavBar.js. All of the youtube videos, tutorials, and websites that I have found are basically teaching me how to script the theme change within the App.js file, but I want to change the entire theme from this file called NavBar.js because that is where the switch is.
Essentially if a user toggles the theme switch within the NavBar component, it changes the theme entirely. So far I am just able to change the background of the body, but I want to change the background on other components (as well as modify their text colors etc.). This code only changes the background of the main body. Could I just have some direction on what I would need to do to accomplish this? Could I just switch CSS style sheets?
export default function Nav(){
const[theme, setTheme] = useState('dark');
const toggleTheme = () => {
setTheme((theme) => (theme === 'dark' ? 'light' : 'dark'));
if(theme === 'dark')
{
document.body.style = 'background: red;';
}
else{
document.body.style = 'background: white;';
}
}
return(
<div className="main-container">
<div>
<Link to="home"><img src={logo} alt="logo" className="nav-icon"/></Link>
</div>
<div className='theme-Switch-container'>
<Switch onChange={toggleTheme}/>
<h4 style={{position: 'relative', display: 'inline'}}>Switch Theme</h4>
</div>
<div>
<NavbarOption icon={searchGlass} alt="search icon" option="Explore"/>
<NavbarOption icon={bell} alt="bell icon" option="Notifications"/>
<NavbarOption icon={profile} alt="profile icon" option="Profile" link="profile"/>
<NavbarOption icon={forums} alt="forum icon" option="Forums"/>
<NavbarOption icon={market} alt="market icon" option="Cybermarket"/>
<NavbarOption icon={livestream} alt="livestream icon" option="Livestream"/>
<NavbarOption icon={analytics} alt="analytics icon" option="Analytics"/>
<NavbarOption icon={gear} alt="gear icon" option="Settings"/>
<NavbarOption icon={help} alt="help icon" option="Help"/>
{/* <Link to="" className="PostBtn">Post</Link> */}
<button className="PostBtn">Post</button>
{/* <div className="PostBtn">
<h3>Post</h3>
</div> */}
</div>
</div>
);
}
Upvotes: 1
Views: 1179
Reputation: 51
If you want to avoid using context you can definitely just use a simple useEffect
to toggle your root class with the theme and use CSS selectors for the component styling variations.
Example
First, a component that has:
theme
theme
useEffect
which re-runs each time the theme is toggled
useEffect
just sets the css class of document.body
to the value of theme
.
const defaultTheme = "light";
const NavBar = () => {
const [theme, setTheme] = useState(defaultTheme);
useEffect(() => {
document.body.setAttribute("class", theme);
}, [theme]);
return (
<nav>
<h3>Navbar</h3>
<Button
className="my-custom-button"
onClick={() =>
setTheme((prev) => (prev === "light" ? "dark" : "light"))
}
>
Toggle theme ({theme})
</Button>
</nav>
);
};
Our custom button component used above is defined as follows
const Button = ({
children,
...props
}: PropsWithChildren<React.ButtonHTMLAttributes<HTMLButtonElement>>) => {
// ...
return <button {...props}>{children}</button>;
};
Using CSS for theming our custom <Button className="my-custom-button" ... />
// global button styles
.my-custom-button {
border-radius: 5px;
padding: 2px 5px;
}
// dark theme button styles
.dark * .my-custom-button {
background-color: black;
color: white;
}
// light theme button styles
.light * .my-custom-button {
background-color: hotpink;
color: black;
}
A codesandbox that demonstrates this in action
Upvotes: 0
Reputation: 1580
add a css class to the body to save the theme state like dark
and in your css file(s), use body.dark
selector to listen to theme changes.
const toggleTheme = () => {
setTheme((theme) => (theme === 'dark' ? 'light' : 'dark'));
document.body.classList.toggle("dark");
}
in css try something like:
body.dark {
background-color: darkred;
}
body.dark .PostBtn {
background-color: black;
color: white;
}
Upvotes: 1
Reputation: 4953
A nice way to solve this issue will be either using redux or useContext API. I would go for useContext to keep it simple.
In your App.js you can set the context like this:
const ThemeContext = createContext(null); // keep in mind that you can set anything to creatContext as default values.
export default function MyApp() {
return (
<ThemeContext.Provider value="dark">
<NavBar/>
// add more components here that can use the default colors
</ThemeContext.Provider>
)
}
and then in any of your components you can consume/use the useContext like this:
function Panel({ title, children }) {
const theme = useContext(ThemeContext);
const className = 'panel-' + theme;
return (
<section className={className}>
<h1>{title}</h1>
{children}
</section>
)
}
function Button({ children }) {
const theme = useContext(ThemeContext);
const className = 'button-' + theme;
return (
<button className={className}>
{children}
</button>
);
}
You can read more about useContext API from here useContext
Hope that helps!
Upvotes: 1
Reputation: 489
There is two way to do.
use useContext to save the theme value and call in App.js
set a state in App.js and change state in NavBar.js
Way 2 would be like:
app.js
const[theme, setTheme] = useState('dark');
...
<NavBar theme={theme} setTheme={setTheme} .../>
...
NavBar.js
function NavBar(props){
const {theme,setTheme} = props
const toggleTheme = () => {
setTheme((theme) => (theme === 'dark' ? 'light' : 'dark'));
if(theme === 'dark')
{
document.body.style = 'background: red;';
}
else{
document.body.style = 'background: white;';
}
}
...
Upvotes: 0