Reputation: 1582
I would like to share styles between my whole webapp.
My Problem: I am using makeStyles
currently like this:
component_A.js
const useStyles = makeStyles({
specific_style: {
padding: '24px',
// etc.
}
})
function foo() {
const classes = useStyles();
return (
<div className={classes.specific_style}>This is a styled div</div>
)
}
component_B.js
const useStyles = makeStyles({
specific_style: {
padding: '24px',
// etc.
}
})
function bar() {
const classes = useStyles();
return (
<div className={classes.specific_style}>This is another styled div</div>
)
}
Therefore, I am having a lot of duplicated code at the moment.
I thought about putting the classes into a theme and access it like {theme.specific_style}
, is this possible? I tried it, but without success so far.
Could someone share a working example with me and those that follows? :)
Possible solutions I thought about:
.js
and import it then, but that doesn't feel right either since I have already access to the theme - and I guess this is where such styles should live.Upvotes: 2
Views: 1966
Reputation: 23
If you plan to create custom utility classes and use them anywhere, you can add them to the theme override and access in your components using the class names.
Add the overrides to mui theme
let theme = createMuiTheme({
overrides: {
MuiAppBar: {
root: {
transform: 'translateZ(0)'
}
}
},
props: {
MuiIconButton: {
disableRipple: true
}
}
});
theme = responsiveFontSizes(theme);
theme.overrides.MuiCssBaseline = {
'@global': {
'.testMe': {
color: 'red'
},
'.container-std': {
[theme.breakpoints.up('lg')]: {
maxWidth: '1200px',
marginLeft: 'auto',
marginRight: 'auto'
}
},
'.container-wide': {
margin: theme.spacing(2, 2)
}
}
};
Inject into your layout
import { theme } from './styles';
import Footer from '../footer/Footer';
export default function Layout(props) {
const { children } = props;
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Grid container direction="column">
<Grid item style={{ height: '70px' }}>
<Header />
</Grid>
<Grid item>
<div>
{children}
</div>
</Grid>
<Grid item>
<Footer />
</Grid>
</Grid>
</ThemeProvider>
);
}
Use them in your Components
export default function HomePage() {
const classes = useStyles();
return (
<Box className={`${classes.hero} container-wide`}>
Upvotes: 0
Reputation: 2693
TL;DR: Based on your discussion, you want to make the styles before passing them to the theme provider:
const useStyles = makeStyles({specific_style: {spacing: 8}, /*more */});
function UseTheme() {
const classes = useStyles();
return (<ThemeProvider theme={classes}><DeepChild /></ThemeProvider>);
}
function DeepChild() {
const theme = useTheme();
return <span className={theme.specific_style}>specific_style spacing</span>;
}
Otherwise, you are passing a raw object instead of a CSS class name. Try your styles in this pastebin.
NL;PR: Now, in terms of style sharing rationale, since the theme provider is internally a context provider, it will reduce component reusability.
There are four styling scopes:
const useStyles = makeStyles(
{'@global': {'.aGlobalStyleClass': {spacing:8} /*more */}
);
function UseTheme() {
const classes = useStyles();
return (<div className="aGlobalStyleClass">);
}
//from MUI's page
const theme = createMuiTheme({
components: {
// Style sheet name ⚛️
MuiButton: {
styleOverrides: {
// Name of the rule
textPrimary: {
// Some CSS
color: 'white',
},
},
},
},
});
Contextual Style component override: this is the one you have been discussing, where you decide whether to override the component initial style, however, the component needs to be a consumer of a theme provider. "Apply it sparingly", perhaps moving your useStyles() to a common parent of the components is a better solution. The main example uses it.
Local Style component override: your common classname={classes.style} or style={}. As mentioned before, the place where useStyles() is called makes a huge difference. Reduce style duplication by moving the style creation up in the component hierarchy.
const useStyles = makeStyles({specific_style: {spacing: 8}, /*more */});
function Parent() {
const classes = useStyles();
return (<><Child1 classes={classes}/><Child2 classes={classes}/></>);
}
function Child1({classes}) {
return <span className={classes.specific_style}>specific_style spacing</span>;
function Child2({classes}) {
return <div className={classes.specific_style}>specific_style spacing</div>;
}
I assume you are torn between contextual and local style overrides. There is a need for both, yet I will make any duplicate style to go away by scaling up the styles along the composition hierarchy since a change in the theme provider will affect all its component subtree.
Upvotes: 1
Reputation: 875
Using theme with the makeStyles()
is one way of sharing styles throughout your filesystem. The makeStyles()
function can accept a function in addition to accepting an object:
const useStyles = makeStyles((theme) => {
root: {
minWidth: '100%',
color: theme.textColor,
}
}
In this way you can use higher level theme components within your styles objects. What you will need to do is create some theme file where you keep all your shared styles, and then import that object in the same way that you would import a component.
import { lightTheme } from './theme';
Other options include using a Theme provider: https://material-ui.com/styles/advanced/
Also you could pass the theme a prop.
Upvotes: 1