Everything you need to know about CSS modules

A CSS module is just a CSS file which gives you the possibility to style components. The most important advantage of CSS modules is that the styles are scoped locally by default, but what does this actually mean?

A CSS module is just a CSS file that gives you the possibility to style components. The most important advantage of CSS modules is that the styles are scoped locally by default, but what does this actually mean?

CSS is easy, right?

I started my web developer journey as a frontend developer, and with time I also started to deal with backend employees. My colleagues from the backend team were laughing that CSS is just a language for just setting margins and colors.

Keep in mind: if you do something more than adding color to headings…

CSS is not easy.

Take a look at the list below. The biggest CSS dangers are described here:

  1. Conflicts between CSS rules
  2. Overwrites
  3. A big CSS stylesheet with unused rules
  4. Side effects

CSS modules to the rescue

Thanks to the fact that CSS modules are scoped locally, the problems described above disappear.

  • no more conflicts
  • no side effects
  • no global scope

An example CSS module

Take a look below at a straightforward example of a CSS module in PWA Studio:

CSS module (this is just a CSS file)

.section {
    padding: 15px;
}
 
.heading {
    font-size: 24px;
    font-weight: bold;
    margin: 15px 0;
}

The sample component which uses these styles:

import React from "react";
import classes from './sample-component.css';
 
const SampleComponent = () => {
    return (
        <div className={classes.section}>
            <h3 className={classes.heading}>This is the sample component tilte</h3>
            <p>This is the sample component paragraph</p>
 
            <h4 className={classes.heading}>This is the sample list:</h4>
            <ul>
                <li>Sample item A</li>
                <li>Sample item B</li>
                <li>Sample item C</li>
            </ul>
        </div>
    )
};
 
export default SampleComponent;

On the third line, we imported a CSS module called sample-component.css as a classes object. Now we are able to use classes from the CSS module as object properties. Take a look at lines 6,7, and 10.

So this is exactly what CSS modules do—they let you use CSS classes as object properties in JSX files.

How does it work?

Thanks to Webpack and the configuration of the loaders, the classes described in the CSS module, and applied in the React component, are rendered as unique CSS classes for each place where they are used.

CSS modules explanation
  1. Here is the place where the section class is applied to the node.
  2. This is a CSS rule which includes CSS properties.
  3. Here you can see a unique class name applied to the node in the compiled app.
  4. This is compiled into a unique CSS rule.

Webpack configuration

Take a look at the webpack configuration. In PWA Studio you can find them in @magento / pwa-buildpack / lib / WebpackTools / configureWebpack / getModuleRules.js file


getModuleRules.css = async ({ paths, hasFlag }) => ({
    test: /\.css$/,
    oneOf: [
        {
            test: [paths.src, ...hasFlag('cssModules')],
            use: [
                'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        localIdentName: '[name]-[local]-[hash:base64:3]',
                        modules: true
                    }
                }
            ]
        },
        {
            include: /node_modules/,
            use: [
                'style-loader',
                {
                    loader: 'css-loader',
                    options: {
                        modules: false
                    }
                }
            ]
        }
    ]
});

On line 11 you can see where the names of the compiled classes come from, and line 12 is where the CSS modules are enabled.

Composition

CSS modules let you compose rules from other rules:

.heading {
    font-size: 24px;
    font-weight: bold;
    margin: 15px 0;
}
 
.secondaryHeading {
    composes: heading;
}

It’s possible to compose multiple selectors:

.section {
    padding: 15px;
}
 
.header {
    background-color: lightgray;
}
 
.heading {
    font-size: 24px;
    font-weight: bold;
    margin: 15px 0;
}
 
.secondaryHeading {
    composes: heading;
}
 
.sampleHeader {
    composes: section header heading;
}

Global CSS Rules

Scoping styles locally is lovely, but sometimes you need to define some global CSS rules, for example for animations (keyframes). CSS modules let us create global rules using the :global() function.

// global-styles.css
:global(.global-class-name) {
    color: red;
}

When you import this CSS module into your app, you will be able to use a global CSS rule like this:

// import stylesheet
import './global-styles.css'
...
// example of using global CSS rule
<p className="global-class-name">This is paragraph with global styles appiled</p>

Composing from global

Sometimes it is necessary to compose from a global rule to a local one, which you can do like this:

.redHeading {
    composes: global-class-name from global
}

Naming conventions

It’s recommended to use the camel case naming convention because using classes in JS, in this case, is easiest. When the name of the class looks. for example, like this: .my-sample-class, then you can apply this class to an element in the following way:

<ul className={classes['my-sample-class']}>

Merging and overrides classes

In PWA Studio you can pass classes as props to a component, and overwrite default component classes with classes from props. Take a look:

import { mergeClasses } from '@magento/venia-ui/lib/classify';
import defaultClasses from '@magento/venia-ui/lib/components/Main/main.css';
 
const Main = props => {
   const classes = mergeClasses(defaultClasses, props.classes);
}

If you pass classes as props, you can validate them using PropTypes:

Main.propTypes = {
    classes: shape({
        page: string,
        page_masked: string,
        root: string,
        root_masked: string
    })
};

Conclusion

In my opinion, locally scoped CSS resolve many problems and is a really nice, modern approach to managing styles. Perhaps for many Frontend Developers, this is a controversial approach, and that’s OK because this is completely different from what is commonly used.

Maybe you have experience with CSS modules? Let me know in the comments!

Thanks for reading. All likes, shares, and comments are really appreciated.

Github repository

You can find examples of the code for this article on my Github.Here is the repository.

Sources

https://magento.github.io/pwa-studio/technologies/basic-concepts/css-modules/

https://github.com/css-modules/css-modules

https://webpack.js.org/loaders/css-loader/#modules

https://x-team.com/blog/css-modules-a-new-way-to-css/

https://glenmaddern.com/articles/css-modules

Share the Post:

You might also like

A career in technology: How to develop your skills

Are you a programmer and would like to grow? The Internet is full of materials on how to do this. Despite this, don’t run away – I have something that will interest you. Did you know that Adam Malysz, the legendary Polish ski jumper, was a roofer before he became a flying champion? I dare not compare myself with Mr. Adam, while there are two things we have in common.

I was also a roofer and also managed to re-brand myself. Maybe not in such a spectacular way, but still. In this article, I’ll share my personal experience on my journey from roofer to programmer to tech lead and give you tips you can apply to grow and advance and maybe even dramatically change your career.

Read More
AHA! Let's bring back the simplicity of the Frontend

AHA! Let’s bring back the simplicity of Frontend

Have you wondered why, in this day and age, when we have access to the latest technologies and solutions, IT projects still fail? Don’t you think that we complicate our lives and work in many cases instead of simplifying it? Sometimes less is more, especially in the world of frontend! Read on to learn what an AHA stack is and how to do frontend more simply.

Read More