I have a component that gets rendered in multiple places. This component will need to have different text color depending on where it gets rendered.
My approach to building the component is to accept a classNames
prop so that I can pass in custom css where ever the component is rendered.
Header.js
export const Header = ({ classNames, lightMode = true, menuIconColor }) => {
const navigate = useNavigate();
const { isNavOpen, setIsNavOpen } = useContext(NavigationContext);
return (
<div className={styles.header}>
<div
className={cx(styles.navBar, classNames, {
[styles["navBar--hidden"]]: isNavOpen,
})}
>
<a className={styles.logoNav}>
<img
className={styles.logo}
src={LogoWithTextLight}
/>
</a>
<div className={styles.navButtons}>
<button className={styles.navButton} onClick={() => navigate("/")}>
HOME
</button>
<button
className={styles.navButton}
onClick={() => navigate("/learn")}
>
LEARN
</button>
<button
className={styles.navButton}
onClick={() => navigate("/about")}
>
ABOUT
</button>
</div>
</div>
</div>
);
};
The header.js file imports styles from ./header.module.scss
This approach works well for passing styles that affect the <div className={styles.header}>
. However I am not able to pass in nested styles to change the styles of divs
nested deeper.
For example I want to pass in css that changes the color of the text onHover.
So when I render my header component on my learn page I pass a css className.
<Header classNames={styles.header} lightMode={false} />
The learn page imports styles from ./learn.module.scss
.
Inside my learn.module.scss
file I have:
.header {
color: rgb(9, 98, 8);
.navBar {
.navButtons {
.navButton {
color: inherit;
font-size: inherit;
font-weight: inherit;
&:hover {
color: black;
}
}
}
}
}
This works to successfully override the header.module.scss
header class style. However the hover
style is not being applied. Additionally I am not able to do any styling directly on the navButton
class.
2
Answers
The reason why your styling doesnt show is due to how scss modules work.
When you inherit classes in this way, your parent class selector (.navButton in learn.module.scss) tries to match the child components scss resolved class name eg .navButton__4jxl.
You can solve this in two ways:
Dont inherit styling, instead inherit props telling the component which ”local” class names to render.
The hacky way. Use wildcard css selectors to target parts of class names, effectivly ignoring the scss module appended part.
E.g.
[class^=”navButton”] {
…
}
Solution 2 gets messy quick and i dont recommend it.
I tried the wildcard classnames solution in a previous project. I realized my mistake and refactored into inheriting non-css props (solution 1.)
Hope this helps!
I would solve this by introducing css variables in the styling for the re-usable component to allow customization; and gradually expanding the API surface as needed.
Here’s an example:
and when you need to customize it