Convert CSS module kebab-case class names to camelCase in Next.js
Asked Answered
M

2

10

I'm using CSS modules (.scss) with Next.js and have a kebab naming-convention. In other words, something like this:

.member-btn {
    background: #fff;
}

The problem that I'm facing is that in order to use this with className I have to do it like styles["member-btn"]. E.g.

<Button className={styles["member-btn"]}>
    Hello world
</Button>

However, I would like to use it with styles.memberBtn and use it like an object (IDE also provides built-in support for this). E.g.

<Button className={styles.memberBtn}>Hello world</Button>

Is this possible in Next.js?

Marsupial answered 12/10, 2022 at 8:1 Comment(2)
Why not to use camel case directly? maybe you can find something here #63693809 or similar questionsPloughboy
@Ploughboy I think kebab-case is more standard when you write css codes.Visser
N
7

Next.js doesn't provide an easy, built-in way to customise CSS Modules options yet (see related RFC vercel/next.js#15818). This means you have to dig into webpack and customise the css-loader used by Next.js directly in your next.config.js.

Here's a potential solution that works for the latest Next.js versions, based off the answers in vercel/next.js#11267.

// next.config.js

module.exports = {
    // other existing configurations here...
    webpack: (config) => {
        const rules = config.module.rules
            .find((rule) => typeof rule.oneOf === 'object').oneOf.filter((rule) => Array.isArray(rule.use));
        rules.forEach((rule) => {
            rule.use.forEach((moduleLoader) => {
                if (
                    moduleLoader.loader !== undefined 
                    && moduleLoader.loader.includes('css-loader') 
                    && typeof moduleLoader.options.modules === 'object'
                ) {
                    moduleLoader.options = {
                        ...moduleLoader.options,
                        modules: {
                            ...moduleLoader.options.modules,
                            // This is where we allow camelCase class names
                            exportLocalsConvention: 'camelCase'
                        }
                    };
                }
            });
        });

        return config;
    }
}

The idea is to target the css-loader used internally by Next.js and overwrite the exportLocalsConvention option to 'camelCase'. This enables the usage of camelCased class names, e.g. styles.memberBtn.

Nematic answered 15/10, 2022 at 23:17 Comment(0)
G
5

This is what solved my issue, it converts all css module classnames to camelCase

// next.config.js

module.exports = {
    webpack: (config) => {
        // camelCase style names from css modules
        config.module.rules
            .find(({oneOf}) => !!oneOf).oneOf
            .filter(({use}) => JSON.stringify(use)?.includes('css-loader'))
            .reduce((acc, {use}) => acc.concat(use), [])
            .forEach(({options}) => {
                if (options.modules) {
                    options.modules.exportLocalsConvention = 'camelCase';
                }
            });

        return config;
    },
};
Gavrah answered 21/10, 2022 at 5:9 Comment(1)
That's much simpler than the overly complicated solutions presented here github.com/vercel/next.js/discussions/11267Glandulous

© 2022 - 2024 — McMap. All rights reserved.