Node + React - Hyphenated CSS Class Names

Node + React - Hyphenated CSS Class Names

- isn't a valid identifier character, so your original code would be evaluated as:

s.header - inner

You haven't defined a variable called inner so you get a reference error.

However any character can be used to make up a key for an object, so you can use a string to access the property you want.

return (
<div className={s['header-inner']}> </div>
);

Dashes in CSS class names with Gatsby v3 (css-loader v5)

So it turns out the issue is with the esModule field in the css-loader options. It is enabled by default and:

generates JS modules that use the ES modules syntax. There are some cases in which using ES modules is beneficial, like in the case of module concatenation and tree shaking.

As far as I understand it, this converts CSS class names into JS variables, which can't have hyphens so instead they are changed to camelcase.

So to keep the hyphens in the CSS class names and use the syntax className={styles["block__element--modifier"]) we need to override the css-loader options with:

options: {
...use.options,
esModule: false,
modules: {
exportLocalsConvention: "asIs",
namedExport: false,
},
},

However I am still running into a build error when passing these options directly to webpack config through gatsby-node.js but have found a workaround using the Gatsby plugin gatsby-plugin-postcss (only 129B minified + gzipped) with these options in gatsby-config.js:

{
resolve: "gatsby-plugin-postcss",
options: {
cssLoaderOptions: {
esModule: false,
modules: {
exportLocalsConvention: "asIs",
namedExport: false,
},
},
},
},

This will produce the warning:

warn You did not set any plugins, parser, or stringifier. Right now, PostCSS does nothing. Pick plugins for your case on https://www.postcss.parts/ and use them in postcss.config.js.

However it's just a warning that doesn't cause any other issues!

With this implementation you will need to import styles using the Gatsby v2 method:

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

Bear in mind that this prevents the default tree shaking behaviour of Gatbsy v3 / css-loader v5.

Also it turns out this was actually covered in the migration guide here. It however does not indicate to use exportLocalsConvention: "asIs" which, from my testing, is required.

React className naming convention

TLDR: PascalCase and Block__Element--Modifier

Check out the official doc of create-react-app. It provides a minimum example of creating a custom component. The js and css filenames as well as the className are all following PascalCase.

// Button.css
.Button {
padding: 20px;
}

// Button.js
import React, { Component } from 'react';
import './Button.css'; // Tell Webpack that Button.js uses these styles

class Button extends Component {
render() {
// You can use them as regular CSS styles
return <div className="Button" />;
}
}

Besides, the doc also provides an external link, which describes BEM naming conventions (link) for elements inside the component.

// MyComponent.js
require('./MyComponent.less');
import { Component } from 'react';
export default class MyComponent extends Component {
render() {
return (
<div className="MyComponent">
<div className="MyComponent__Icon">Icon</div>
...
</div>
);
}
}

// MyComponent.less
.MyComponent__Icon {
background-image: url('icon.svg');
background-position: 0 50%;
background-size: fit;
height: 50px;
}

Which casing should I use for CSS classes when using CSS-in-JS?

In React first one always works in case of modules, so you do not need to worry about it. So, going with the below convention works fine.

React:

import style from './style.module.css'
//...
<Button className={style.myButton} />

CSS

.myButton {
background-color: blue;
}

Refer to this Medium link for more insight:
CSS in JS

How to call SCSS 'parent selector reference &' to react css module?

If you use dash in an object's properties name(in this case, it's class name), for use of it you must use Bracket notation, and your property name should be in ' '(quotation or double-quotation).

<div className={layout['br--red']}>
<h1>Khan</h1>
</div>

You can read more about it in this article.

babel-plugin-react-css-modules is not matching styles with styleName

Found the solution myself after some struggling.

Cause

This is due to a quirk of css-loader: if there are double quotes around localIdentName option, it will wrap the generated class name with hyphens.

Working Examples

So instead of doing this in webpack config:

{
test: /\.(scss|sass)$/,
use: [
'style-loader?sourceMap',
'css-loader?modules="true"&importLoaders="1"&localIdentName="[path]___[name]__[local]___[hash:base64:5]"',
'sass-loader?sourceMap',
],
},

Do this:

{
test: /\.(scss|sass)$/,
use: [
'style-loader?sourceMap',
'css-loader?modules="true"&importLoaders="1"&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
'sass-loader?sourceMap',
],
},

Or event better if you are using Webpack 2+

{
test: /\.(scss|sass$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true,
sourceMap: true,
localIdentName: '[path]___[name]__[local]___[hash:base64:5]'
}
},
'sass-loader'
]
}

Next.js: How to change CSS Modules classes output format?

Next.js doesn't yet provide a built-in way to modify the css-loader options.

However, you can still do so by customising the webpack configuration in your next.config.js. You'll need to manually go through each css-loader module loader and add the desired localIdentName.

// next.config.js

module.exports = {
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'
) {
delete moduleLoader.options.modules.getLocalIdent;
moduleLoader.options = {
...moduleLoader.options,
modules: {
...moduleLoader.options.modules,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
// You can also add other css-loader options here
}
};
}
});
});

return config;
}
};


Related Topics



Leave a reply



Submit