How to use environment variables in ReactJS imported CSS? - css

I created a simple React app using https://github.com/facebookincubator/create-react-app.
I am trying to specify a configurable URL to a component's CSS like this:
.Cell {
background-image: url({process.env.REACT_APP_STATIC_URL}./someImage.png);
}
And here's the component:
import React from 'react';
import './Cell.css'
class Cell extends React.Component {
render() {
return (
<div className="Cell">
{this.props.name}
</div>
);
}
}
But it doesn't look like the process variable trickles down to the imported CSS. How would I go about doing this?

If you want to use js variables in CSS, try React inline-style instead of plain css file.
https://facebook.github.io/react/tips/inline-styles.html
If you want to separate CSS and JS, you might need a CSS preprocessor to manage your global variables.

I came across one such scenario, The method I used is instead of adding it as background in CSS, make an img element and assign the path as src in component itself. I don't think there is any other way of doing that.

Commenting on this as I've recently had a similar issue. This should work to send an image file as a CSS variable in a build.
use the style prop to invoke a CSS style
Use template literal around the url() value
use the Javascript require() to refer to the file in the final build pack. Using a relative url requires that you call the image relative to where the the page will be called instead of being relative to the component JS file.
In the React component, use the inline style prop to set the CSS variable:
<div
style={{"--img":`url( ${require("../../images/coding.jpg")})`}}>
</div>
in the CSS file:
background-image: var(--img);

Related

Issue with :global() css-module selectors not being pure in NextJS

So I'm migrating an app from CRA to NextJS and I have encountered an error for the .module.scss files of some components and pages:
Syntax error: Selector ":global(.label-primary)" is not pure (pure selectors must contain at least one local class or id)
I get this error for all the :global and :local css-module selectors. Based on what I have searched I can fix this issue by wrapping the selector in a class and editing the jsx aswell. but wouldn't that defeat it's purpose?
And how is this working on the CRA version of the app and not on NextJS?
EDIT:
One solution I have for this is moving :global() selectors to the global css files that are imported in _app.js but my question is that is there any way that we can have so these styles would be usable like they are right now ( :global(...) )?
No there isn't any solution as of yet other than overriding the webpack config itself. It was working in CRA because they probably have mode: local, while Next.js has pure.
I haven't tried overriding css-loader webpack config, so I am simply suggesting a workaround. Since, you are using SCSS, you can wrap your pseudo-global [1] styles like this:
.root :global {
.foo {
color: red;
}
}
Now wrap your component/page in a div and set the class as styles.root on that element. Then, on all the child elements you can directly set className="foo".
import styles from "../styles/index.module.scss";
const IndexPage = () => (
<div className={styles.root}>
<div className="foo">This text should be red!</div>
</div>
);
export default IndexPage;
Note that, you need to consider issues regarding specificity after this method, also this doesn't directly work with animations, you need to separate the keyframes and then make them global.
Demo Sandbox
[1]: This method doesn't make the styles truly global as the styles are still scoped. The class foo will work only when some parent has styles.root as class. This is preferrable only if you didn't intend to use your :global(.selector) from other components, and were using them just because you wanted to manipulate the class names using JS without the styles object.
If you want these to be truly global, add styles.root to document.documentElement in an useEffect hook like this:
import { useEffect } from "react";
import styles from "../styles/index.module.scss";
const IndexPage = () => {
useEffect(() => {
document.documentElement.classList.add(styles.root);
return () => {
document.documentElement.classList.remove(styles.root);
};
}, []);
return (
<div className="foo">
This text should be red, even if you put it in another component until the
page is same. If you want it across pages inject it in _app or _document.
</div>
);
};
export default IndexPage;
Demo Sandbox
PS: Injecting class to html in _app or _document is not exactly same as using a global stylesheet, as it may happen that you have multi-page application, then only the CSS of the components on a particular page will be requested because of automatic CSS code-splitting done by Next.js. If that's not the case and all your pages share same CSS, then there is no need to complicate things, just go with the conventional method of importing styles in _app.
I had the same problem, the right writing is
.root:global {
color:red
}
Another approach is to make a container, wrap it, and carry it out like follows:
import style from '../styles/style.module.css'
<div className={styles.container}>
<p>Hello World</p>
</div>
.container p {
font-size: 20px;
}
And yes, you only need to include your tags and conditions in the CSS file if you have a lot of them.

Why does CSS styling disappear in React when directly changing route in browser URI?

I have a simple front-end React app created using npx create-react-app. The app is using react-router-dom routes. When I directly change the URI in the browser from say, localhost:3000/ to localhost:3000/search it will navigate to the <Route>but with no CSS rendered; just HTML from the component.
How can I make sure CSS is rendered in the new route when directly navigating in the browser? My future goal is to be able to copy and paste a route in a new tab and navigate to the correct page and display results from an API.
Css style sheets will need to be imported either at the root level or within the file itself.
style sheets need to be imported when used and then the corresponding classname will need to be used within the component or tag.
Another useful way to set react css without style sheets is by using in line styles
e.g
<div style ={{float: "right", textAlign : "center"}}> </div>
EDIT
A really easy way to get styles going within a react project is install bootstrap.
then buttons and stuff can be assigned classNames such as
<div className = "jumbotron"></>
this will leave a grey box around the items.
<div className = "btn btn-primary"></>
this will give you a blue styled button.
Any more information or help within your application let me know and provide some code snippets.
You can use styled-components. styled-components are widely used in ReactJs and React Native and it's a perfect choice.
styled-component : https://www.npmjs.com/package/styled-components
I realized that react apps created using npx create-react-app allow you to import a css module for components.
Given the component, Button.jsx, you can simply create a css module with the convention, [module-name].module.css. For the case of Button.jsx, create a file named Button.module.css, import "styles" from the module. Styles will be an object containing all the CSS styles.
I if I had a folder named "components" with all my components, I could make a folder within "components", say called "compStyles", and create all the [module-name].module.css files in there.
Button.module.css:
/* class names must be camelCased */
.myButton {
margin: 0 auto;
}
span {
fontSize: 20px;
}
If I had the above mentioned file structure, I could import and use like so:
import React from 'react';
import styles from './styles/Button.module.css';
const Button = () => {
return (
<div className={styles.myButton}>
<button><span>Some Button</span></button>
</div>
)
}
export default Button;
Styles for the span will be automatically applied, and any other class will be referenced by styles.className. Create one file for every component, and each component's CSS will take care of itself and not break like it would if it was in the public folder.

How to stylize web compoenent inside react app?

I have my react app inside which i want to use vaadin-date-picker (v. 4.0.5).
I want to change some of the date pickers in a way that they would be above my modal by changing z-index to 1100 (for example)
and some to stay at 200.
In some examples, people put <style> tag inside
<vaadin-date-picker></vaadin-date-picker>
But react is not recognizing <style> attribute inside render function.
I can set class for
<vaadin-date-picker class='my-class'>
but it only changes control itself and not the backdrop part. Is there a way to change styles of some web components inside react app?
Make sure you are importing the file correctly
import './yourcssfile.css'; // if in same directory
also in react classes are applied using className keyword
<vaadin-date-picker className="my-class">
and lastly you have to follow the documentation vaadin. you can't add your own styles if the vaadin-date-picker doesn't support it.
Here in their documentation it says Vaadin Date Picker comes with both Lumo and Material design themes, and it can be customized to fit your application.
The cleanest way to use styles in my opinion is to use CSS files, so
import './classname.css';
Would be my default answer. However, if you want to set styles explicitly in your Component, these are two examples, how you can do it:
class Example extends Component {
getStyle1 = () => {
return {
fontWeight: 'bold'
};
}
render () {
return (
<div><div style={this.getStyle1()}>style1</div>
<div style={style2}>style2</div></div>
)
}
}
const style2 = {
fontStyle: 'italic'
}
Remember that it's JavaScript objects that you return with your styles, so you don't use CSS syntax with dashes (e.g. you type backgroundColor instead of background-color) and all values must be put in quotes.

Change global css in react-router based on routes?

There's a global css class I want to override (.ant-content), but I want to do it per route, I've tried importing css files which override .ant-content per react-component that gets loaded up in various routes but they only end up loading their css even when not rendering (probably because the imports happen regardless if a component is loaded).
Assuming you have a class like this somewhere which you want to override:
.ant-content{
color: red
}
you could try using the specifity ordering rules of CSS to override this. So, for example if in one of your routes you have a component you want to overwrite which looks like this
<div className='override'>
<Component className='ant-content/>
</div>
Then in the CSS you import into that component you could use:
.override .ant-content{
color: blue
}
This should override the original .ant-content class as it is more 'specific' than the original class declaration.
You can read more about specifity here: https://www.w3schools.com/css/css_specificity.asp

using css modules, how can I import classes from a file

I am using css modules for my project, and I have a file positioning.css which has some useful classes that I want to import. e.g. .right, .left
What is the best approach for this using CSS Modules?
At the moment I can see 2 options, but they are not all that great:
composition in the component's style
.right {
composes: right from '../styles/positioning.css';
}
or
multiple css module imports in the component
import positioning from '../styles/positioning.css'
import styles from './myComponent.css';
Object.assign(styles, positioning)
class Menu extends Component {
render() {
return (
<div styleName='menu'>
<div styleName='left'>this is left</div>
<div styleName='right'>this is right</div>
</div>
);
}
};
export default CSSModules(Menu, styles);
I have manage to get this working:
// css file
#value class-to-compose from "file-where-class-is-defined.css";
.someclass {
composes: class-to-compose;
// other styles
}
One approach is to collect all app level css variables and calculations at the top level into app.css
#import "./theme/layout.css";
#import "./theme/colors.css";
...
Then reference app.css using
#import "../../app.css";
This way you can manage #import scope inside one file at the root level.
I'll go with the first proposition. (the result is quiet the same)
both proposition have quiet the same result
If someday you have to edit your Menu css, you'll just have to edit your Menu css and not your component.
You let CSSModules take decisions. (more futur proof?)
You could import the css files that you use frequently into a broader CSS file that you import on specific pages, this is taking the second approach but making it cleaner, especially if you have a lot of common core css files that you import on pretty much all pages.
I would advise you to go with [Sass] [1]. Sass allows for the usage of partials (i.e. distributed / scoped css sheets).
You write scoped (to the components you want) css and import all your partials into your main.css then.
Couple of other advantages:
you can do theming by having one partial that defines your them via variables, which you import first and then all your partials can use these variables.
having the css on a scoped level (at least to me) felt more "reactish" where components are supposed to be stand alone, but it also wasn't inline styling, which I find ugly and weird (I don't like to clutter down my .js files with styles)
[1] http://sass-lang.com/
I find this one line very helpful with importing:
#import 'file.css';
You could set these as globals and update their names to be a tad more semantic, like BootStraps pull-right.
If you declare them as
:global(.right) {
/* ... */
}
You can then just use them in your app by preferably importing globals early on in the entry point.
You should take a look at the option by vue.js component (scoped/overall)
You can choose a precompile css language like SASS, which can use #extend ...etc to reuse the common property, like below:
%common {
width: 100%;
height: inherit;
}
.my-class {
#extend %common;
}

Resources