CSS Modules

While CSS Modules can be used with Melody, they don't have to be used. It is up to you to decide whether you want to go down this route or not.

What are CSS Modules?

CSS Modules allow you to use CSS without relying on a global scope which can be very useful in an application setting or when you intend to create reusable components, since it avoids potential name clashes.

You can find more documentation about the concept here: https://github.com/css-modules/css-modules

How to configure Webpack?

You can find a quick and small example of how to configure Webpack and Melody to enable CSS Modules here: https://github.com/pago/melody-demo-css-modules/blob/master/webpack.config.js#L21

Using CSS Modules in Melody

Melody supports CSS Modules indirectly. It offers a statement that can be used to import them. However, you'll need to configure Webpack appropriately to be able to truly use them.

{% import './home.css' as styles %}
<div class="{{ styles.home }}">
    <div class="{{ styles.logo }}">
        <svg xmlns="http://www.w3.org/2000/svg" width="270" height="270" viewBox="0 0 270 270">
            <circle cx="135" cy="135" r="135" fill="#272361"></circle>
            <path d="M146.14 87.94a45 45 0 0 0-53.24 53.23L48.08 186a9 9 0 1 0 3.38 3l42.79-42.79a45 45 0 0 0 9.34 16l-24.05 24.03a9 9 0 1 0 3.19 3.18l24.05-24.05a45 45 0 0 0 16 9.34l-11.43 11.43a9 9 0 1 0 3.26 3.1l13.18-13.18a45 45 0 0 0 18.35-88.12z" fill="#6eceb2"></path>
            <circle cx="152.46" cy="100.5" r="13.5" fill="#fff"></circle>
            <circle cx="150.46" cy="102.5" r="4.5" fill="#272361"></circle>
            <circle cx="173.96" cy="117" r="9" fill="#fff"></circle>
            <circle cx="171.96" cy="117" r="3" fill="#272361"></circle>
            <path d="M140.2 34.39a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM73.94 62.38a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM206.45 62.38a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM234.45 128.64a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM200 201.62a4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0 4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0z" fill="#6eceb2"></path>
        </svg>
    </div>
    <h1 class="{{ styles.title }}">
        {{ message }}
    </h1>
</div>

Importing only some classes

Instead of importing the entire CSS module into a variable you can also import specific CSS classes.

{% from './home.css' import home, logo as logoClass, title %}
<div class="{{ home }}">
    <div class="{{ logoClass }}">
        <svg xmlns="http://www.w3.org/2000/svg" width="270" height="270" viewBox="0 0 270 270">
            <circle cx="135" cy="135" r="135" fill="#272361"></circle>
            <path d="M146.14 87.94a45 45 0 0 0-53.24 53.23L48.08 186a9 9 0 1 0 3.38 3l42.79-42.79a45 45 0 0 0 9.34 16l-24.05 24.03a9 9 0 1 0 3.19 3.18l24.05-24.05a45 45 0 0 0 16 9.34l-11.43 11.43a9 9 0 1 0 3.26 3.1l13.18-13.18a45 45 0 0 0 18.35-88.12z" fill="#6eceb2"></path>
            <circle cx="152.46" cy="100.5" r="13.5" fill="#fff"></circle>
            <circle cx="150.46" cy="102.5" r="4.5" fill="#272361"></circle>
            <circle cx="173.96" cy="117" r="9" fill="#fff"></circle>
            <circle cx="171.96" cy="117" r="3" fill="#272361"></circle>
            <path d="M140.2 34.39a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM73.94 62.38a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM206.45 62.38a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM234.45 128.64a4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0 4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0zM200 201.62a4.45 4.45 0 0 1 0-6.36 4.62 4.62 0 0 1 6.47 0 4.45 4.45 0 0 1 0 6.36 4.62 4.62 0 0 1-6.47 0z" fill="#6eceb2"></path>
        </svg>
    </div>
    <h1 class="{{ title }}">
        {{ message }}
    </h1>
</div>

By using the logo as logoClass syntax you can specify a different name for the imported CSS class. This helps to avoid naming conflicts.

Use with the classes filter

When working with CSS classes, you'll often want to use the classes filter for improved ergonomics.

{% import './styles.css' as styles %}
<button type="button" class="{{ {
        base: styles.button,
        (styles.primary): isPrimary
} | classes }}">{{ text }}</button>

The above example will add the styles.primary class if the isPrimary property is true.

Using multiple classes

While the imported class names are just strings and can be concatenated easily (class="{{ styles.button }} {{ styles.buttonSmall }}") the ergonomics behind that are less than ideal and you'd be working around CSS modules instead of leveraging its full potential.

It is advisable to compose CSS classes within the CSS so that within the template you'll only ever need to work with one of them (unless you're dealing with modifiers like in the example above).

{% import './buttons.css' as styles %}
<button type="button" class="{{ styles.button }} {{ styles.buttonSmall }}">
    Not ideal
</button>

<button type="button" class="{{ styles.secondaryButton }}">
    Much better
</button>

Both buttons will have the styles.button and the styles.buttonSmall classes but by leveraging the composes functionality offered by CSS Modules, we've been able to create a more meaningful, semantically valuable class name: styles.secondaryButton. And we've increased our separation of concern since the template no longer needs to know how such a secondary button is composed together from different CSS classes.

Last updated

Was this helpful?