I have a React component utilizing Material-UI called 'Profile', with custom CSS to create responsive font sizing like such:
let theme = createMuiTheme();
theme = responsiveFontSizes(theme);
theme.typography.h1 = {
fontSize: '5.35rem',
'#media (min-width: 600px)':{
fontSize: '3.0rem',
},
'#media (max-width: 600px)':{
fontSize: '2.2rem'
},
[theme.breakpoints.up('md')]:{
fontSize: '5.35rem'
}
}
The first few lines of the return are:
export default function Profile () {
return (
<div>
<ThemeProvider theme={theme}>
<Grid container direction="row">
<Grid item className="profile">
When I include this component in my index.js file, it renders perfectly. However, once I add a new component called 'PublicWorks.js' as such:
<React.StrictMode>
<Header />
<Profile />
<PublicWorks />
</React.StrictMode>,
the responsive styling no longer works. The code for PublicWorks is very simple, essentially just this (with appropriate closing brackets):
import React from 'react';
import {Grid, Typography, Accordion, AccordionSummary, AccordionDetails, ThemeProvider} from '#material-ui/core';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
export default function PublicWorks () {
return (
<div>
<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />} >
<Typography>Project 1</Typography>
</AccordionSummary>
<AccordionDetails>
Is this overriding caused by the nature of MuiTheme operating at more of a global scale, or am I doing something else incorrectly? Should I be trying something like:
<React.StrictMode>
<ThemeProvide theme={theme}>
<Header />
<Profile />
<PublicWorks />
</ThemeProvide>
</React.StrictMode>,
in order to implement this correctly?
I think the problem you are having may be correlated with this issue.
Regardless, in general you would need to use the ThemeProvider as parent of your components since it uses React Context
This component takes a theme property, and makes it available down the
React tree thanks to the context. It should preferably be used at the
root of your component tree.
Docs: https://material-ui.com/styles/api/#themeprovider
Regarding your comment And if I just want it in Profile?
You can use other solutions such as makeStyles for this if you opt to style that component separately
Related
could someone please help me with this issue.
this is the code:
import { AppBar } from "#mui/material";
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles({
root: {
backgroundColor: 'red'
}
})
const App = () => {
const classes = useStyles();
return <>
<AppBar className={classes.root}>
test
</AppBar>
<h1 className={classes.root}>test</h1>
</>
}
export default App;
The question is:
why the background-color of the AppBar component is not changing;
No problem with the h1 tag thought;
The other problem I've found is, sometimes it changes, but when I refresh the page, it becomes blue -> color by default;
So, thanks a lot for the answer if there is any :);
I faced a similar issue where styles applied to the AppBar component did not override some of the default styles. The fix was to wrap my component tree with <StyledEngineProvider injectFirst>. The solution looks something like this in the end:
import React from 'react';
import { StyledEngineProvider } from '#mui/material/styles';
export default function GlobalCssPriority() {
return (
<StyledEngineProvider injectFirst>
{/* Your component tree. Now you can override MUI's styles. */}
</StyledEngineProvider>
);
}
Link to source
<AppBar className={classes.root}>
test
</AppBar>
instead wrap your text in a div and use className on that div
<AppBar >
<div className={classes.root}>
test
</div>
</AppBar>
I'm using styled-components in my React app and wanting to use a dynamic theme. Some areas it will use my dark theme, some will use the light. Because the styled components have to be declared outside of the component they are used in, how do we pass through a theme dynamically?
That's exactly what the ThemeProvider component is for!
Your styled components have access to a special theme prop when they interpolate a function:
const Button = styled.button`
background: ${props => props.theme.primary};
`
This <Button /> component will now respond dynamically to a theme defined by a ThemeProvider. How do you define a theme? Pass any object to the theme prop of the ThemeProvider:
const theme = {
primary: 'palevioletred',
};
<ThemeProvider theme={theme}>
<Button>I'm now palevioletred!</Button>
</ThemeProvider>
We provide the theme to your styled components via context, meaning no matter how many components or DOM nodes are in between the component and the ThemeProvider it'll still work exactly the same:
const theme = {
primary: 'palevioletred',
};
<ThemeProvider theme={theme}>
<div>
<SidebarContainer>
<Sidebar>
<Button>I'm still palevioletred!</Button>
</Sidebar>
</SidebarContainer>
</div>
</ThemeProvider>
This means you can wrap your entire app in a single ThemeProvider, and all of your styled components will get that theme. You can swap that one property out dynamically to change between a light and a dark theme!
You can have as few or as many ThemeProviders in your app as you want. Most apps will only need one to wrap the entire app, but to have a part of your app be light themed and some other part dark themed you would just wrap them in two ThemeProviders that have different themes:
const darkTheme = {
primary: 'black',
};
const lightTheme = {
primary: 'white',
};
<div>
<ThemeProvider theme={lightTheme}>
<Main />
</ThemeProvider>
<ThemeProvider theme={darkTheme}>
<Sidebar />
</ThemeProvider>
</div>
Any styled component anywhere inside Main will now be light themed, and any styled component anywhere inside Sidebar will be dark themed. They adapt depending on which area of the application they are rendered in, and you don't have to do anything to make it happen! 🎉
I encourage you to check out our docs about theming, as styled-components was very much built with that in mind.
One of the big pain points of styles in JS before styled-components existed was that the previous libraries did encapsulation and colocation of styles very well, but none of them had proper theming support. If you want to learn more about other pain points we had with existing libraries I'd encourage you to watch my talk at ReactNL where I released styled-components. (note: styled-components' first appearance is at ~25 minutes in, don't be surprised!)
While this question was originally for having multiple themes running at the same time, I personally wanted to dynamically switch in runtime one single theme for the whole app.
Here's how I achieved it: (I'll be using TypeScript and hooks in here. For plain JavaScript just remove the types, as, and interface):
I have also included all the imports at the top of each block code just in case.
We define our theme.ts file
//theme.ts
import baseStyled, { ThemedStyledInterface } from 'styled-components';
export const lightTheme = {
all: {
borderRadius: '0.5rem',
},
main: {
color: '#FAFAFA',
textColor: '#212121',
bodyColor: '#FFF',
},
secondary: {
color: '#757575',
},
};
// Force both themes to be consistent!
export const darkTheme: Theme = {
// Make properties the same on both!
all: { ...lightTheme.all },
main: {
color: '#212121',
textColor: '#FAFAFA',
bodyColor: '#424242',
},
secondary: {
color: '#616161',
},
};
export type Theme = typeof lightTheme;
export const styled = baseStyled as ThemedStyledInterface<Theme>;
Then in our main entry, in this case App.tsx we define the <ThemeProvider> before every component that's going to use the theme.
// app.tsx
import React, { memo, Suspense, lazy, useState } from 'react';
import { Router } from '#reach/router';
// The header component that switches the styles.
import Header from './components/header';
// Personal component
import { Loading } from './components';
import { ThemeProvider } from 'styled-components';
// Bring either the lightTheme, or darkTheme, whichever you want to make the default
import { lightTheme } from './components/styles/theme';
// Own code.
const Home = lazy(() => import('./views/home'));
const BestSeller = lazy(() => import('./views/best-seller'));
/**
* Where the React APP main layout resides:
*/
function App() {
// Here we set the default theme of the app. In this case,
// we are setting the lightTheme. If you want the dark, import the `darkTheme` object.
const [theme, setTheme] = useState(lightTheme);
return (
<Suspense fallback={<Loading />}>
<ThemeProvider theme={theme}>
<React.Fragment>
{/* We pass the setTheme function (lift state up) to the Header */}
<Header setTheme={setTheme} />
<Router>
<Home path="/" />
<BestSeller path="/:listNameEncoded" />
</Router>
</React.Fragment>
</ThemeProvider>
</Suspense>
);
}
export default memo(App);
And in header.tsx we pass the setTheme to the component (Lifting the state up):
// header.tsx
import React, { memo, useState } from 'react';
import styled, { ThemedStyledInterface } from 'styled-components';
import { Theme, lightTheme, darkTheme } from '../styles/theme';
// We have nice autocomplete functionality
const Nav = styled.nav`
background-color: ${props => props.theme.colors.primary};
`;
// We define the props that will receive the setTheme
type HeaderProps = {
setTheme: React.Dispatch<React.SetStateAction<Theme>>;
};
function Header(props:
function setLightTheme() {
props.setTheme(lightTheme);
}
function setDarkTheme() {
props.setTheme(darkTheme);
}
// We then set the light or dark theme according to what we want.
return (
<Nav>
<h1>Book App</h1>
<button onClick={setLightTheme}>Light </button>
<button onClick={setDarkTheme}> Dark </button>
</Nav>
);
}
export default memo(Header);
Here's something that did the job for me:
import * as React from 'react';
import { connect } from 'react-redux';
import { getStateField } from 'app/redux/reducers/recordings';
import { lightTheme, darkTheme, ThemeProvider as SCThemeProvider } from 'app/utils/theme';
import { GlobalStyle } from 'app/utils/globalStyles';
interface ThemeProviderProps {
children: JSX.Element;
isLightMode?: boolean;
}
const ThemeProvider = ({ children, isLightMode }: ThemeProviderProps) => {
return (
<SCThemeProvider theme={isLightMode ? lightTheme : darkTheme}>
<React.Fragment>
{children}
<GlobalStyle />
</React.Fragment>
</SCThemeProvider>
);
};
export const ConnectedThemeProvider = connect((state) => ({
isLightMode: getStateField('isLightMode', state)
}))(ThemeProvider);
I have GlobalStyle with some overwrites like:
const GlobalStyle = createGlobalStyle`
h6 {
font-weight: ${props => (props.semibold ? 600 : "bold")};
font-size: 16px;
}
...
`;
I would like to pass props from my components to GlobalStyle for eg. weight. Something like this (from JSX):
const LocalComponent = () => {
return (
<div>
<h6 semibold>This should be semi-bold text</h6>
</div>
);
};
above example doesn't work ofc. But is there a way to achieve this?
Currently I'm wrapping h6 into another SC, and adding font-weight locally. It would be much better to have it on global scale without need to create another component just as a wrapper for bold text etc.
Based on the above information, it isn't clear what part is missing.
I am presuming you have added the <ThemeProvider theme={your_theme} /> as a wrapper around your application (e.g. <App />) This will inject props into all of your styled-components if they are children of <App />.
<ThemeProvider theme={your_theme}>
<GlobalStyle />
<App />
</ThemeProvider>
Don't forget to add your <GlobalStyle /> component as a child to the ThemeProvider, or the props will not populate.
I have my react application where I want to apply MUI darkBaseTheme. Without it, part of my app looks like this:
After I wrap all the html stuff in my render() with:
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
</MuiThemeProvider>
Having those imports:
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; // add
import RaisedButton from 'material-ui/RaisedButton'; // add
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
It looks like this:
So it changed RaisedButtons. I know it shouldn't change html ones. But why didn't it change the background to dark? Is there a way to do this, or do I have to do it manually without MUI?
You need to include the <CssBaseline /> component at the root of your app as this is what deals with changing the background colour on the body.
Docs
I had a similar issue. The body background was not changing when I switched to dark mode.
Solution:
Move your CssBaseline inside MuiThemeProvider. Otherwise the body background won't change when you use type dark in your theme.
<MuiThemeProvider theme={theme}>
<CssBaseline />
<App />
</MuiThemeProvider>
MUI v5 Update
You can change the background to a dark color by setting the mode property to dark, and include the CssBaseline which sets the backgroundColor of the body element:
const theme = createTheme({
palette: {
mode: 'dark',
},
});
<ThemeProvider theme={theme}>
<CssBaseline />
<Content />
</ThemeProvider>
If you want to use a custom color for the background:
const theme = createTheme({
palette: {
background: {
default: 'gray',
},
},
});
My question is very simple, I want to use the Material-ui default darkTheme in a part of my app. Here is a sample of code :
<div>
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<div>
<AppBar title="I am dark" />
<MyCustomComponent label="I should be dark but I am not" />
</div>
</MuiThemeProvider>
<MuiThemeProvider muiTheme={getMuiTheme(lightBaseTheme)}>
<p>I am in the lightBaseTheme (default theme)</p>
</MuiThemeProvider>
</div>
The first part of the app must be in the dark theme (that's a left menu), the second part in the light theme (that's the app itself).
The AppBar that is a direct child of the MuiThemeProvider is indeed dark, however, MyCustomComponent and its children (even when they are base Material-ui components such as RaisedButton) are not using the dark theme.
What is the simplest way to have MyCustomComponents and all its sub-children to use the dark theme too ?
You need to wrap all inside MuiThemeProvider into one element.
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<div>
<AppBar title="I am dark" />
<MyCustomComponent label="I should be dark but I am not" />
</div>
</MuiThemeProvider>
actually you had to have an error like
MuiThemeProvider.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
Of course only Material-UI components inside your MyCustomComponent will have themed appearance. Everything else you need to make manually: in a way shown by Jeff McCloud or by using context like this:
function MyCustomComponent (props, context) {
const { palette } = context.muiTheme;
// Now you have access to theme settings. for example: palette.canvasColor
}
MyCustomComponent.contextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
One more way to stylize plain HTML or React Components is to wrap them into
react-theme-provider. Like this:
import ThemeProvider from 'react-theme-provider';
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<div>
<AppBar title="I am dark" />
<ThemeProvider>
<MyCustomComponent label="I should be dark and I am!" />
</ThemeProvider>
</div>
</MuiThemeProvider>
reference: https://github.com/callemall/material-ui/blob/master/src/styles/MuiThemeProvider.js#L7
You need to designate that your custom component is "themeable". You do this by wrapping your component in the 'muiThemeable' Higher-Order Component:
import React from 'react';
import muiThemeable from 'material-ui/styles/muiThemeable';
class MyCustomComponent extends React.Component {
// ... your component will now have access to "this.props.muiTheme"
}
export default muiThemeable()(MyCustomComponent);
reference: http://www.material-ui.com/#/customization/themes