Search code examples
reactjssassnext.jscss-modules

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


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?


Solution

  • 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.