How to change theme dinamically in react application - reactjs

I'm trying to change the theme of my react application from light to dark (and viceversa) using a button or a switch button (I will decide it later). The fact is: I'm importing the themes' .css directly from bootswatch (I'm currently using "Minty" as the light theme and I want to use "Darkly" as the dark theme (https://bootswatch.com/)). For now I only found that there is the ThemeProvider component but it needs the theme as a .js file in which you must export what you want (and I can't do it since I only have the .css). I also found a ThemeSwitcher on github (https://github.com/raythree/react-bootstrap-theme-switcher) but it seems it's using bootstrap v3 and I actually need v4. There is also a thread on Reddit that suggests to import them in the public folder and change them (https://www.reddit.com/r/reactjs/comments/9lzm8g/react_switching_themes_css/) but I don't think it's a good practice. Can anybody help me?
edit: I tried the reddit solution: now it's changing the theme but for an instant I can definitely see some pure html things that I don't like at all.
This is my code
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Tabs from "./Tabs";
import "react-toastify/dist/ReactToastify.min.css";
import { Helmet } from "react-helmet"
export const Application = () =>{
const [theme, setTheme] = useState(true)
const changeThemeHandler = (event) => {
event.preventDefault();
setTheme(!theme)
}
return(
<>
<button onClick={(event) => changeThemeHandler(event)}>Change Theme</button>
<Helmet>
<link rel="stylesheet" href={`${process.env.PUBLIC_URL}/${theme ? 'lightbootstrap.min.css' : 'darkbootstrap.min.css'}`} />
</Helmet>
<Tabs />
</>
)
}
ReactDOM.render(<Application />, document.getElementById("root"));
How can I adjust it in order to have a smooth transition from light to dark theme and viceversa?

Related

The JSX import source cannot be set without also enabling React's "automatic" JSX transform

I'm trying to use Material UI icons inside my Qwik website.
I used the answers of If possible, how to use MUI with Qwik framework? and here's my Icons.jsx file:
/** #jsxImportSource react */
import { qwikify$ } from '#builder.io/qwik-react'
import AcUnitIcon from '#mui/icons-material/AcUnit'
import MenuIcon from '#mui/icons-material/Menu'
import AddIcon from '#mui/icons-material/Add'
import RemoveIcon from '#mui/icons-material/Remove'
import DriveFileRenameOutlineOutlinedIcon from '#mui/icons-material/DriveFileRenameOutlineOutlined'
export const MuiAcUnitIcon = qwikify$(() => <AcUnitIcon />)
export const MuiMenuIcon = qwikify$(() => <MenuIcon />)
export const MuiDriveFileRenameOutlineOutlinedIcon = qwikify$(() => <DriveFileRenameOutlineOutlinedIcon className='text-white' />)
export const MuiAddIcon = qwikify$(({ sx, className }) => <AddIcon sx={sx} className={className} />)
export const MuiRemoveIcon = qwikify$(({ sx, className }) => <RemoveIcon sx={sx} className={className} />);
Everything works great in the development. But when I want to build the app for the production environment using npm run build or npm run preview, I get this error:
The JSX import source cannot be set without also enabling React's "automatic" JSX transform
And every component that has used the MUI icon would render as a blank space on my website.
I also tried How to fix vite warning: The JSX import source cannot be set?, but it made no difference.
Here's the issue that we wrote for the Qwik team. And here's a reproducable repository.
What should we do to fix this?

How to access MUI 5 theme variables in deep functional component?

The MUI 5 docs on Theming have a section on "Accessing the theme in a component". However, it's really just one sentence that links to the legacy style docs.
Here's the example they give in those legacy docs:
import { useTheme } from '#mui/styles';
function DeepChild() {
const theme = useTheme();
return <span>{`spacing ${theme.spacing}`}</span>;
}
Which is pretty much exactly what I want to do — I want to be able to access the theme color palette down in some deep functional component. However, my component complains
Module not found: Error: Can't resolve '#mui/styles' in...
Digging a little further, it seems they're rather strongly trying to discourage people from using this legacy Styles technique, and the MUI 5 way to do this is with "system design tokens", which I guess should Just Work. But, they're not.
I have my whole app wrapped in ThemeProvider:
import React from 'react';
import { CssBaseline } from '#mui/material';
import { ThemeProvider } from '#mui/material/styles';
import theme from './theme';
import Foo from './foo';
const App = () => {
return (
<Fragment>
<ThemeProvider theme={theme}>
<CssBaseline enableColorScheme />
<Foo />
</ThemeProvider>
</Fragment>
);
};
export default App;
And then in foo.js:
import React from 'react';
import { Box } from '#mui/material';
export const Foo = () => {
return (
<Box
sx={{
background: 'repeating-linear-gradient(-45deg, '
+ ' theme.palette.error.light, theme.palette.error.light 25px,'
+ ' theme.palette.error.dark 25px, theme.palette.error.dark 50px'
+ ')',
}}
>
<span>Test</span>
</Box>
);
};
I initially started with just error.light and error.dark. When that didn't work, I expanded it all to palette.error.light, etc..., and then ultimately to theme.palette.error.light, etc....
It seems no matter what I try, it's not accessing those theme variables, and is instead just passing through the text.
So, back to the question: how am I supposed to access MUI 5 theme variables in nested functional components?
Replace
import { useTheme } from '#mui/styles';
with
import { useTheme } from '#mui/material/styles';
#mui/styles is used for legacy, you can add it using yarn add or npm install, but first give a shot to what I mentioned above.

Some elements not responding to the costum theme in materialUI

So when I apply a custom theme in materialUI (specifically changing the font) some of the components change the font and some don't and I don't know why. Basically, all the imported components that use the <Typography> component don't get the applied theme if they are nested inside other materialUI components or not.
import classes from "./App.module.css";
import Form from "./components/Form";
import Text from "./components/Text";
import { createTheme, ThemeProvider } from "#material-ui/core";
const theme = createTheme({
typography: {
fontFamily: "Grey Qo",
fontSize: 25,
},
});
function App() {
return (
<div className={classes.wrapper}>
<ThemeProvider theme={theme}>
<Text></Text>
<Form></Form>
</ThemeProvider>
</div>
);
}
export default App;
enter image description here
In the picture you can see the form font and the top button change becuase they dont use the <Typography> component but the rest stay the same
Here is also an example of the React <Text> component which is imported
import { Typography } from "#mui/material";
import { makeStyles } from "#material-ui/styles";
import React from "react";
import classes from "./Text.module.css";
const useStyles = makeStyles({
text: {
color: "#f0f0f0",
},
});
export default function Text() {
const uiClasses = useStyles();
return (
<div className={classes.wrapper}>
<Typography variant="h4" className={uiClasses.text}>
Learn code by watching others
</Typography>
<Typography className={uiClasses.text}>
See how expirienced developers solve problems in real-time. Watching
scripted tutorilas is great, but understanding how developers thinks is
invalubale
</Typography>
</div>
);
}
This font is used to make the problem more obvious, hope someone can help. tnx in advanced
Maybe because you imported Text.module.css or the other css files are overriding the font family that is set by material theme, you can inspect elements to the one that does not apply the correct font to know exactly where is the style come from.
One more important thing is when using material there's a jss implementation that is the makeStyles you're using, it would be awesome and good enough for you to work with. so you don't have to use css module anymore. Hope my hint can help you!

Use antd for React together with Storybook v5

Now, I am stuck for several hours trying to make Storybook work with antd in my new React application (created with create-react-app), without success.
Whatever I do, Storybook does not take the styling of antd.
For example, I created a menu item with antd:
menuNav.tsx:
import React from "react";
import {Menu} from 'antd';
import "antd/dist/antd.less";
const MenuNav = () => {
return (
<Menu mode="horizontal">
<Menu.Item key="menu1">
This is my menu title
</Menu.Item>
</Menu>
)
}
export default MenuNav;
But the result looks like this, no styling at all, but a list:
And as you can see here, it understands that the menu is created by the UI library, but there is no antd styling applied:
This is the story file of MenuNav, 3-Menu.stories.js:
import React from "react";
import MenuNav from '../components/MenuNav';
export default {
title: "MenuNav",
component: MenuNav,
};
export const Text = () => <MenuNav></MenuNav>
I already tried to add a config.js inside ./storybook as suggested here, with no success. Furthermore, I tried adding a webpack.config.js in the same directory as recommended here, same result.
What am I doing wrong?
try adding #import '~antd/dist/antd.css'; to your applications main file, let say index.css which for example is placed in src folder and then add import '../src/index.css'; to .storybook/preview.js
`

How to use styled-components theme in Gatsby 2.0

so as the title says I'm curious what is the best practise of adding a styled-components theme to Gatsby website? I've been searching through the internet without finding a definite answer but from what I've gathered I probably should do it by creating a layout in src/layouts/index.tsx that wraps all the pages with the ThemeProvider:
import * as React from 'react'
import { ThemeProvider } from 'styled-components'
import { defaultTheme } from '../theme/defaultTheme'
export const DefaultLayout = ({ children }) => (
<ThemeProvider theme={defaultTheme}>
{ children }
</ThemeProvider>
)
And then I'm able to use theme freely in my styled components? Which doesn't work and I'm getting a bit frustrated with this.
Ok well the solution was simple. Since I was following the old examples done with v1 I guess I should have known that the layouts are not automatically added in v2. Sigh so that layout works but I just have to add it manually:
import { DefaultLayout } from '../layouts/DefaultLayout'
...
<DefaultLayout>
<div>
<h1>Front page</h1>
<Button>I am a button</Button>
</div>
</DefaultLayout>
Hmmph frustrating bug but maybe that was on me.

Resources