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
Aptana Studio 3 Code Assist for SASS (.Scss) Files
Style the First <Td> Column of a Table Differently
How to Use Calc() in Tailwind CSS
Including Margin for Width and Height
What Is the Purpose of Using Font: Inherit
Position:Sticky Is Not Working
Using Nth-Child in Tables Tr Td
Two HTML Tables Side by Side, Centered on the Page
How to Use SCSS/Sass to Increase Animation-Delay for Concurrent Divs
What Is the Regex of a CSS Selector
CSS Relative + Right (Or Bottom) Almost Never Work
Why Do I Get the Error Message "Element 'Style' Cannot Be Nested Within Element 'Style'"
Django-Bower + Foundation 5 + SASS, How to Configure
Validationsummary and Validationmessagefor with Custom CSS Shown When No Errors Present
How to Control Size of List-Style-Type Disc in CSS