Implementation

Since CSS Modules is just CSS with some build-time webpack magic, there can’t be any problems with using it for AMP.

To use the future’s CSS today, I used postcss-preset-env. Also, I wanted to benefit from my favorite features in the CSS-in-JS stack, like theme-based styles, style props, etc.

Theming is a big issue in general. The power of new CSS features, such as CSS variables and custom media queries, helps a lot here. With postcss-preset-env, you don’t need to worry about browser support either. All you need to do is create a theme.css file with CSS variables and provide this file to the postcss-preset-env config. Here are my config and a sample theme file.

With this setup, you can define any variable for your theme globally and use it in your styles. Theming problem solved. Next.

As I mentioned before, I’m a really big fan of style props. There are libraries like classnames and clsx to help you use props to create dynamic classes. Let’s see an example.

As you can see, there’s a lot of boilerplate code even for a very basic component. But wait a second. Can you see the pattern? There are style props, prop values, and relative CSS classes. It seems that with some conventions, helper functions, and components, we can create a small generic library for this task.

First of all, we need some conventions.

Use .root class as a base.

class as a base. Use .{prop}-{value} convention for style props. E.g. .color-primary

convention for style props. E.g. Use .{prop} convention if the prop value is boolean

To benefit from these conventions, we need a function that gets a set of props and a styles object, and then maps style props to the styles object using the clsx library.

With this helper function, we don’t need to write all that boilerplate code. Let’s refactor the button component using mapPropsToStyles function.

// Button.css

.root {

...

} .color-primary {

background-color: var(--primary-color);

} .color-secondary {

background-color: var(--secondary-color);

} .size-small {

padding: var(--space-2);

} .size-medium {

padding: var(--space-4);

} // Button.js

import mapPropsToStyles from 'src/common/mapPropsToStyles';

import styles from './Button.css'; export default function Button({ color, size, ...props }) {

const classes = mapPropsToStyles({ color, size }, styles); return <button className={classes} {...props} />;

}

Much better, right? Yeah, but we can even take it one step further and create a generic component to take care of all styling work for us.

.

With this approach, we don’t need to take care of styling boilerplate for every component. We can create any element we want with as prop, and we can pass additional classes with className prop to add and overwrite styles. Let’s refactor our button component for the final time.

Now our life is much simpler and our components are neat. All we need to do is write a CSS file and pass matching props to our component.