There are multiple ways to achieve customized styling and two come to mind (as well as a third after some research). There are other ways to do this as well. The first two options do this without CSS-Modules. The third is an attempt to solve this problem using CSS-Modules.
Option 1
Pass styles from a parent component to a child component. You can update the styles
dynamically in the parent and pass it to the child. Because you are passing an object as a prop, this can potentially cause unnecessary re-renders and harm performance. Inline styles are nice because they are easy to dynamically create and pass as props. They are the de facto way to pass dynamic styles.
import React, { CSSProperties } from 'react';
interface CSSStyles {
[key: string]: CSSProperties;
}
const MainComponent = () => {
const styles: CSSStyles = {
header: { marginLeft: "10px" }, // Dynamically update
icon: { marginRight: "10px" }, // Dynamically update
myComponent: { color: "black" }, // Dynamically update
};
return (
<>
<SomeCustomComponent cssClasses={styles} />
</>
);
};
interface Props {
cssClasses: CSSStyles;
}
const SomeCustomComponent = ({ cssClasses }: Props) => {
return (
<div style={cssClasses.myComponent}>
<p style={cssClasses.header}>Header</p>
<Icon style={cssClasses.icon} />
</div>
);
};
Option 2
You can pass a className
as a string and update it in the parent. This requires you to make multiple classes in your .scss
file. Since the cssClasses
prop is passing an object here, this can also potentially cause unnecessary re-renders. You can tweak this if performance becomes and issue.
.tsx
interface CSSStyles {
[key: string]: string;
}
const MainComponent = () => {
const styles: CSSStyles = {
header: "header", // Dynamically change
icon: "icon", // Dynamically change
myComponent: "myOtherComponent", // Dynamically change
};
return (
<>
<SomeCustomComponent cssClasses={styles} />
</>
);
};
interface Props {
cssClasses: CSSStyles;
}
const SomeCustomComponent = ({ cssClasses }: Props) => {
return (
<div className={cssClasses.myComponent}>
<p className={cssClasses.header}>Header</p>
<Icon className={cssClasses.icon} />
</div>
);
};
.scss
.myComponent {
color: white;
.header {
margin-left: 10px;
}
.icon {
margin-right: 10px;
}
}
.myOtherComponent {
color: black;
.header {
margin-left: 100px;
}
.icon {
margin-right: 100px;
}
}
Option 3
A CSS-Module Specific way. Looks like you can:
- Wrap each child in a div
- Pass the className as props
- Use the CSS child combinator
- Create multiple CSS classes and pass the className (similar to option 2).
These seem to be specific to CSS-Modules, but seem more complex than option 1 or 2. I am not certain of the performance implications for the CSS-Modules.
See https://stackoverflow.com/a/55082008/9931154 and https://stackoverflow.com/a/34036086/9931154 for references. The CSS-Modules documentation didn't seem to mention anything relating to your problem.