'What's the 'correct' way to override styles from parent when using CSS Modules?
I am using NextJS with CSS Modules to manage styles.
I would like to modify the appearance of a component when it is:
- Rendered normally on a page, using props to specify modifiers for className.
- Rendered within a specific parent component
- Rendered within a specific parent component as props.children.
I have a working solution for all of the above, but I'd like to know if any of these techniques are considered bad practice, or if there is a better alternative I should be considering (Particularly for scenario 3).
Using a simple Button component as an example:
Scenario 1:
button.module.scss
.button {
color: 'black';
}
.red {
color: 'red';
}
.blue {
color: 'blue';
}
Button.jsx
import styles from './button.module.scss';
const Button = (props) => {
const classNames = [styles.button];
props.modifiers.map((modifier) => {
classNames.push(styles[modifier]);
});
return (
<button className={classNames.join(' ')}>{props.text}</button>
);
}
export default Button;
Page.jsx
<Button text={`Test`}/>
<Button text={`Test`} modifiers={[`red`]}/>
<Button text={`Test`} blue={[`red`]}//>
Scenario 2:
This time, I need to change the styling of the Button component when it appears within ParentComponent (sometimes combined with the previous technique).
parent-component.module.scss
.button {
background-color: 'green';
}
ParentComponent.jsx
import styles from './parent-component.module.scss';
import Button from 'components/button/Button.jsx';
const ParentComponent = (props) => {
return (
<>
<Button text={`Test`} modifiers={[styles.button}>
<Button text={`Test`} modifiers={[`red`, styles.button]}>
</>
);
}
Button.jsx has to be updated to deal with this
props.modifiers.map((modifier) => {
// The modifier doesn't exist in the local styles, so we apply it directly
classNames.push(styles[modifier] || modifier);
});
Scenario 3:
ParentComponent.jsx
import styles from './parent-component.module.scss';
const ParentComponent = (props) => {
return (
<div>{props.children}</div>
);
}
// Expose styles on the exported component, so we can refer to it in page.jsx
ParentComponent.styles = styles;
export default ParentComponent;
Page.jsx
<ParentComponent>
<Button text={`Test`} modifiers={[ParentComponent.styles.button]}>
</ParentComponent>
I'm coming from a BEM background, where I'd normally use something like this to solve this issue: (Source https://css-tricks.com/using-sass-control-scope-bem-naming/)
.component {
$self: &;
display: block;
max-width: 30rem;
min-height: 30rem;
&--reversed {
background: white;
border-color: lightgray;
// Here, we use $self to get the correct scope
#{ $self }__child-element {
background: rebeccapurple;
}
}
}
Any advice appreciated.
Solution 1:[1]
Use the npm package classnames.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alex Mckay |
