Skip to main content

CSS Modules

In TaskFlow, we will write our CSS using CSS Modules. This is an intuitive way of writing CSS, as it is equal to writing regular CSS with a few extra perks. CSS Modules are locally scoped, meaning one doesn’t have to worry about name collisions in different files. To use them you simply provide a className (in camelCase) which you can import in your component and use. It is advisable to decide on a naming convention which your whole team uses, to ensure consistency and readability.

Creating your css-module

As CSS Modules is supported by Next.js, you can simply create your first CSS Module like so:

Navigation.module.css
.container {
background: skyblue;
height: fill-available;
position: fixed;
width: 100vw;
}

We're using position: fixed and height: fill-available so the height for mobile devices will fill the screen properly.

Now we're going to import all our classes in our Navigation component at once using import styles from './Navigation.module.css'. Using import styles is the way CSS Modules lets us import all classes from our module.css file.

Navigation.jsx
import styles from "./Navigation.module.css";

const Navigation = () => {
return (
<div className={styles.container}>
<h1>Hi 👋</h1>
</div>
);
};

Notice that the container class is prefixed by styles which makes sure that we are using the container class coming from our imported module.css file.

Conditional styling

To change the styling of our navigation, we can simply use Javascript inside the className={} brackets to determine what styles are being applied when, for example, isActive=true

const Navigation = () => {
const [isActive, setIsActive] = useState(false);

return (
<div className={`${styles.container} ${isActive && styles.active}`}>
<h1>Hi 👋</h1>
</div>
);
};

Here we can access the isActive variable by breaking out of the so-called template literal in the className and applying the styles by wrapping them inside ${}.

.container {
background: skyblue;
height: 32px;
position: fixed;
width: 100vw;
}

.active {
height: fill-available;
}

Composition

In certain situations you can choose to compose a new class based on another class. This allows you to build a new class out of the styles defined by other pre-defined classes. Let's take the .active class as an example, but now with composition:

.container {
background: skyblue;
height: 32px;
position: fixed;
width: 100vw;
}

.activeContainer {
composes: container;
height: fill-available;
}

And rewrite the logic in the className.

const Navigation = () => {
const [isActive, setIsActive] = useState(false);

return (
<div className={isActive ? styles.activeContainer : styles.container}>
<h1>Hi 👋</h1>
</div>
);
};

This time, we didn't need to break out the template literal. .activeContainer overrides the height property from .container but still has background-color: green, position: fixed and width: 100vw.

It's up to you to decide when to use composition or just add a new class to the className that overrides or adds a certain property.

Further reading