Referencing css class in React component when it has - - reactjs

hi if I have a css class imported into my React component as below:
import classes from './stylesheet.css'
How can I reference it, if the class has - in it?
<div className={classes.Content}></div>
Like for example if the class name is Content-LI if it is, how can I reference it? I mean reference it using classes in the above, it threw me error when I tried to reference it using
<div className={classes.Content-LI}></div>
It says undefined LI, any help please? thank you.

try <div className={classes["Content-LI"]}></div>

If you are trying to use modular css structure, First you need to configure css module in webpack.
Find the module block from webpack config and add this line:
{
test: /\.css$/,
loader: 'style-loader'
}, {
test: /\.css$/,
loader: 'css-loader',
query: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
}
Then you can import css to your component like this:
import styles from './app.css';
<div className={styles.app}>
<p>This text will be blue</p>
</div>
I have found this for more information. Hope its help for you :)

Related

Module scss ampersand class selector not working

I have a simple scss file with
.navItem {
cursor: pointer;
&.active {
color: $primaryPurple;
}
&:hover {
color: $primaryPurple;
}
span {
margin-left: 10px;
}
}
For some reason, the :hover works but .active doesn't work. As you can see in the image below, li clearly has the active class but I don't see the font color css changed.
TL;DR: Pass the name as a JavaScript Object, not like a simple string.
Actually, this issue comes from the css-modules configuration. Obviously, based on the AdminSideBar_navItem__1aFBc in the embed picture. your css-modules configuration in the Webpack config is:
// webpack config
module.exports = {
~~~
module: {
~~~
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]_[local]_[hash:base64:5]', // <=== Attention to this line
sourceMap: true,
}
},
~~~
],
}),
],
},
~~~
};
So, when you are using css-modules it means you will have so professional advantages like a more compressed css bundle file or full hashed unreadably uglified bundle. for these benefits, you should use CSS class names like a JavaScript object, pay attention to the following ReactJS code alongside using css-modules:
import React from 'react';
import cn from 'classnames'; // <=== install it to have easy coding
import styles from '[pathToScssFiles]/styles.scss';
const MyComponent = ({ isActive }) => (
<li className={cn(styles.navItem, isActive && styles.active)} />
);
I hope, you understand my point, you passed the styles.active as a simple string: "active". so css-modules cannot get your class name as an object and pass it exactly like what it got, as a simple string, hence, "active" **BUT** in the CSS bundle file the css-modulesuse the'[name][local][hash:base64:5]'` pattern to deform its name.
Your :hover should work and it works because anyone cannot change it, it's a pseudo-class.
For sure, write a weird property for .active:
.navItem {
cursor: pointer;
&.active {
fill: yellow;
}
Now seek for the fill: yellow in the CSS bundle that Webpack makes for you. you see it is:
.AdminSideBar_navItem__1aFBc .AdminSideBar_active__9be2a {
fill: yellow;
}
Note: the ~~~ means etc.
Providing you jsx code would help, but I will take a guess that you use active as a string literal, so your code looks like
import styles from './componentName.module.css';
// and then in the component
<li className={`nav-item ${styles.AdminSideBar_navItem} ${whateverCondition ? 'active' : ''}`}>
...children...
</li>
The problem here is that active class also has a suffix just like AdminSideBar_navItem. And in order to make it work you need to access it the same way you access AdminSideBar_navItem. So the code should be
<li className={`nav-item ${styles.AdminSideBar_navItem} ${whateverCondition ? styles.active : ''}`}>
...children...
</li>
and in html you will see
<li class="nav-item AdminSideBar_navItem_abcd active_bcde">
I dropped a simple example in this codesandbox, you can play around with it and see how it works.

Import SVG as a component in Gatsby

I've seen the following solution:
import { ReactComponent as Img } from 'path/to/file.svg'
But in Gatsby, this doesn't work. I know exist plugins for this, but maybe it can be done more easily.
As you said, there are plugins to achieve this, which means a cleaner code (not the full SVG tag inlined in the component) with the same final result. Using gatsby-plugin-react-svg plugin you just need to import your SVG like this:
import Icon from "./path/assets/icon.svg";
To install, you only need to add the dependency using npm or yarn and in your gatsby-config.js use this snippet:
{
resolve: 'gatsby-plugin-react-svg',
options: {
rule: {
include: /assets/
}
}
}
Note that /assets/ is an including rule based on a regular expression so the value must be your SVG folder (i.e: /svg/) and must only contain .svg files. In other words, if your path is /images/svg/ your including rule can only contain /svg/ (you can also add the full path but you'll need to escape slashes).
Afterward, you will need to style the SVG if their inline styles don't apply.
If you want to follow the non-plugin approach you can simply use a React-based approach, just creating a component that returns the SVG:
export const YourSvgComponent = () => (
<svg
version="1.1"
baseProfile="full"
width="300"
height="200"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="100%" height="100%" fill="red" />
<circle cx="150" cy="100" r="80" fill="green" />
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">
SVG
</text>
</svg>
);
Now you just need to import it and use it.
Add new package:
npm install gatsby-plugin-react-svg
or
yarn add gatsby-plugin-react-svg
Configure at gatsby-config.js:
{
resolve: 'gatsby-plugin-react-svg',
options: {
rule: {
include: /\.inline\.svg$/,
},
},
},
Here's an example of what this file might look like when completed
module.exports = {
siteMetadata: {
title: `Gatsby`,
},
plugins: [
{
resolve: 'gatsby-plugin-react-svg',
options: {
rule: {
include: /assets/,
},
},
},
],
};
Rename your files to something like example.inline.svg
Import:
import Illustration from './illustration.inline.svg'
Usage:
<Illustration className="example" />
All the information from official Gatsby guide
Just do like this...
import YourDesiredName from 'path/to/file.svg'

Antd Theme is being overridden when used in Gatsby

I am currently trying to customize Antd theme by using the antd and less plugins for Gatsby. Following this thread - Change the Theme of Antd when using GatsbyJS
gatsby-config.js plugins contain
{
resolve: 'gatsby-plugin-antd',
options: {
style: true
}
},
{
resolve: `gatsby-plugin-less`,
options: {
javascriptEnabled: true,
modifyVars: {
'primary-color': '#BADA55'
}
}
}
gatsby-node.js and relevant modules are filled as seen in the thread.
When I look at an element in the browser debugger, the button uses the base theme, but the specified theme is actually there (just being overridden).
I had the same issue and for me it was that I had somewhere in my code imported the style for antd
import "antd/dist/antd.css"

css-loader returns undefined on importing css file

I have a css file named App.css which has css like
.abcd {
margin-top: 50px !important;
color: red !important;
}
I am importing this and using in my react app like
import styles from './App.css'
console.log("style", styles) // it gives object.
<div className={"ui equal width grid " + styles.abcd}>
</div>
Here styles.abcd is showing undefined but when I console styles it gives object with that classname on array.. I dont know what is missing here.
My webpack conf looks like:
{
test: /\.css$/,
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
},
},
I have also tried
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
Nothing is working. Why is it giving undefined ?
Similar problem answered here: CSS Modules class names undefined
In the docs, it's mentioned that you have to name the file as follow :
[name].module.css
Try renaming the file to : Catalog.module.css and import it like this :
import styles from './Catalog.module.css';
In your case you should name it App.module.css and import as such.
Your code is :
import styles from './App.css'
console.log("style", styles) // it gives object.
<div className={"ui equal width grid " + styles.abcd}>
</div>
Here it should have been :
<div className={`ui equal width grid ${styles.abcd}`}>

webpack + mobx + React : require an observable array of images

I am using mobX to store arrays of images for a gallery like this :
#observable peopleThumb = [
'src/assets/photos/people/thumbs_1.jpg',
'src/assets/photos/people/thumbs_2.jpg',
'src/assets/photos/people/thumbs_3.jpg',
etc...
]
Where I have my thumbnails array, the full images array and the mobile images array.
Then I map through the array and use them either as background images or in an image tag in my components (urls are passed down via props) :
<img src={url} />
or
background: `url(${url}) no-repeat center center`,
But when I build for prod since the images are not required and the urls stays like src/assets/photos/people/' they obviously won't be displayed
So I tried simply requiring them :
<img src={require(url)}/>
and
background: `url(${require(url)}) no-repeat center center`
But I get an error :
Uncaught Error: Cannot find module 'src/assets/photos/people/full_3.jpg'.
I tried changing the path in my store to a relative path :
#observable peopleThumb = [
'../assets/photos/people/thumbs_1.jpg',
'../assets/photos/people/thumbs_2.jpg',
'../assets/photos/people/thumbs_3.jpg',
etc...
]
And same error :
Uncaught Error: Cannot find module '../assets/photos/people/full_2.jpg'.
My webpack config for my output and the file loader :
output: {
path: "./build/",
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js'
},
{
test: /\.(jpg|png|svg)(\?.*)?$/,
loader: 'file',
query: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
When I import single images via Import everything works fine but I am stuck when it comes to this observable. I also tried the require context but I honestly didn't really understood what I was doing and I think I should be able to simply require my images once mapped.
Thanks.

Resources