styled-components can be quite nice for whipping up components but for old farts like me that are more familiar with old-timey CSS, I prefer to use CSS Modules.
When using CSS Modules, we quickly find out that while somethings are simpler (media queries) some things are not so easy (how the $@^% do I use a theme?).
Theming
styled-components has a ThemeProvider which is nice. Grab some JSON from a server somewhere and pass it to the ThemeProvider and you can use it in your styles.
We can do that, too. First, we make a Theme Context component. The entire thing is 4 lines, one line is blank and we probably don't even need the first line, anyway...
import { createContext } from "react";
export const ThemeContext = createContext();
export const ThemeProvider = ThemeContext.Provider;
To use it, we import the ThemeProvider, then wrap it around some JSX that we need to style:
import { ThemeProvider } from "./ThemeContext";
<ThemeProvider value={theme}>
<Button>Press</Button>
</ThemeProvider>
Here is a simplified example of a Button component using the theme:
import React, { useContext } from "react";
import styles from "./Button.module.css";
import { ThemeContext } from "./ThemeContext";
export const Button = (props) => {
const theme = useContext(ThemeContext);
const style = {
"--bg-color": theme.backgroundColor,
"--fg-color": theme.foregroundColor,
...props.style
};
return (
<button
className={styles.Button}
style={style}
/>
);
};
The values we need in the theme are passed to the CSS through the style attribute. The CSS module can use the CSS variables like so:
.Button {
color: var(--fg-color);
background-color: var(--bg-color);
}
Adapting Based On Props
Sometimes you want to change the styles on a component based on some props. This becomes quite easy with CSS.
<Button size="large">
Primary Large
</Button>
CSS
.Button {
font-size: 14px;
}
.Button[data-size=large] {
font-size: 16px;
}
Window.matchMedia
The last trick is rather rare, but I ran into an issue where a breakpoint was not known in advance and I had to use logic in javascript to determine if a class should be added to a component or not.
Window.matchMedia allowed me to solve this problem.
This allowed my component to accept a breakpoint
prop and add a CSS class if the window was sized smaller than the breakpoint.
const maxWidth = width =>
window.matchMedia(`(max-width: ${width}px)`).matches;
const getItemClasses = breakpoint => {
const names = [styles.Item];
if (maxWidth(breakpoint)) names.push(styles.ItemSmall);
return names.join(" ");
};
return (
<div className={getItemClasses(breakpoint)}>{children}</div>
);
Conclusion
These tricks covered the features of styled-components that I used but allowed me to use CSS Modules instead. I hope you find them useful.
Top comments (0)