How to make React CSS import component-scoped? - css

I have several components which have the following CSS/component structure
About/style.css
.AboutContainer {
# Some style
}
p > code {
# Some style
}
And I import the CSS in the componet as follows
About/index.js
import './style.css';
export default class About extends Component {
render() {
# Return some component
}
}
However, the CSS is imported in the <header> section and stays global-scope.
I was expecting CSS to be:
Component-scoped in a way that the style is only applied to things that are only rendered within this component.
Style for this component would disappear if the component is unmounted.
However, when inspecting from the browser, the styles are specified at the <header> section and gets applied to all the components
<header>
// Stuff
<style type="text/css">style for component About</style>
<style type="text/css">style for component B</style>
<style type="text/css">style for component C</style>
// Stuff
</header>
How do I import CSS to be component-scoped? It seems like I'm understanding CSS import in React ES6 incorrectly.
I was following this tutorial
Edit
Answer by Brett is correct. However, my problem turns out to be somewhere else. I created my app using create-react-app which basically simplifies setups required to do React. It include WebPack, Babel and other things to get started. The default WebPack config that it uses did not set module option for the css-loader so it defaulted to false, and as a result the local-scoping was not enabled.
Just for additional info, it seems like create-react-app does not have straightforward way to customize WebPack config, but there seem to be numerous how-to workarounds on the web.

It sounds like CSS Modules, or many of the other CSS-in-JS packages, does what you want. Others include Emotion (my current favorite), Styled Components, or many of the packages here.
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. All URLs (url(...)) and #imports are in module request format (./xxx and ../xxx means relative, xxx and xxx/yyy means in modules folder, i. e. in node_modules).
Here's a quick example:
Let's say we have a React component like:
import React from 'react';
import styles from './styles/button.css';
class Button extends React.Component {
render() {
return (
<button className={styles.button}>
Click Me
</button>
);
}
}
export default Button;
and some CSS in ./styles/button.css of:
.button {
border-radius: 3px;
background-color: green;
color: white;
}
After CSS Modules performs it's magic the generated CSS will be something like:
.button_3GjDE {
border-radius: 3px;
background-color: green;
color: white;
}
where the _3DjDE is a randomly generated hash - giving the CSS class a unique name.
An Alternative
A simpler alternative would be to avoid using generic selectors (like p, code, etc) and adopt a class-based naming convention for components and elements. Even a convention like BEM would help in preventing the conflicts you're encountering.
Applying this to your example, you might go with:
.aboutContainer {
# Some style
}
.aboutContainer__code {
# Some style
}
Essentially all elements you need to style would receive a unique classname.

Maybe react-scoped-css will help. Btw, I'm the author of this lib, if you find anything broken or simply want to improve it, you can always raise an issue or send a pr.

Because you mentioned you used create-react-app, the solution here is quite easy change just style.css to style.module.css, it will look like this:
import styles from "./style.module.css"
<button className={styles.button}>blabla</button>
More info on this article:
https://blog.bitsrc.io/how-to-use-sass-and-css-modules-with-create-react-app-83fa8b805e5e

You can use SASS (.scss) to imitate scoped CSS.
Say you need to use bootstrap in only one component (to avoid conflicts). Wrap the component in <div className='use-bootstrap'> and then created a .scss file like so:
.use-bootstrap {
// Paste bootstrap.min.css here
}

Use this file naming convention [name].module.css
and see documentation: https://create-react-app.dev/docs/adding-a-sass-stylesheet
JSX File
import React from 'react';
import styles from './index.module.scss';
const MyPage = () => {
return (
<div className={styles}>
<h1>My Page</h1>
</div>
);
};
export default MyPage;
Styles File
h1 {
color: #f3f3f3;
font-family: "Cambria";
font-weight: normal;
font-size: 2rem;
}

For me, the simple solution (without using: Css-modules or css-in-js) is to add a suffix to your class selectors like this:
className="btn__suffix"
if your component is named: FileUpload.tsx so your __suffix would be __fu, i took the first character of each word (here: File and Upload).
the end result would be:
import './style.css';
export default class About extends Component {
render() {
Return (
<div className="container__fu">
...
</div>
)
}
}
And in the Css part, your file would be:
.container__fu {
...
}

I created a rollup plugin to have scoped scss/css within a vite react project with regular import, you can check it out if it can solve your issue!
https://www.npmjs.com/package/rollup-plugin-react-scoped-css

Related

Module '"*.css"' has no exported member 'CompaniesLogo'. Did you mean to use 'import CompaniesLogo from "*.css"' instead?

this may code.
import { CompaniesLogo,navigation,NavLinkGroup } from "./Navigation.module.css";
How can I import the needed classes from css into React ?
That's the way how you need to use as suggested by #qaismakani.
But if you want to component specific styles you can try react-jss
You don't have to explicitly import individual css classes. Import your css file like this:
import "./Navigation.module.css";
and then just start using your css classes.
In your Navigation.module.css file you'll have class styling normally (I assume) like this:
.CompaniesLogo {
// styles here
}
.navigation {
// more styles here
}
. NavLinkGroup {
// even more styles here
}
At the top of your react component file you'll import the css file like #qaismakani mentioned:
import "./Navigation.module.css";
Then, you'll use that css file just like you would in normal HTML, but instead of the class attribute you'll use className instead:
<div className="navigation">This is a navigation Div</div>

How to make visible private classes into specific stylesheet?

Is it possible to access css classes from css modules in a specific css stylesheet? For example I have mediaQueries.css witch I want to connect at the end of my markup of components, but I can't see within mediaQueries.css private classes of aboute.module.css or index.module.css. So how can I configure webpack or what can I do?
Import them as an object and reference the classes as properties:
import styles from "./path/to/stylesheet.module.css";
export default function Component() {
return <div className={styles.className}>hello world</div>
}
Example CSS:
.className {
color: red;
}
For regular stylesheets just import the CSS file:
import "./path/to/stylesheet.css";

How to load different .css files on different components of a react application?

I have two .jsx files that represent their respective components.
The first one is, Blog.jsx
import React from "react";
import '../assets/css/blog.css';
export const Blog = () => (
<div>
<h1>Hello Blog</h1>
</div>
)
With its respective CSS file, blog.css
div { background: #ff481f; }
and the second one is, Landing.jsx
import React from "react";
import '../assets/css/landing.css'
export const Landing = () => (
<div>
<h1>Hello Landing</h1>
</div>
)
With its respective CSS file, landing.css
div { background: #86ff2b; }
I have added routing and called instances of those two components on the App.js file which is the default file of a React application. After running the application, when navigated to components, I faced a problem that the background color is the same for both of the components (It loads landing.css only and never changes).
How can I fix that problem that each component only uses its respective .css file and loads it?
By default webpack and other build tools will compile all CSS files into one, even if css was imported in separate JSX files. So you can't use different CSS files and expect you don't affect on another part of page.
You have some options:
Use BEM for naming class names.
Use cssModules. In this case elements will have their own css class name and styles will not affect any other elements except if you use :global selector.
css-module
Using html tags as css selectors is a bad practice (because there is the behaviour you describe).
You should use only css classes or inline styles (using id's is another bad practise, id's have high priority).
div {
width: 20px;
height: 20px;
}
#id {
background: red;
}
.class {
background: green;
}
<div id="id" class="class"></div>
In case using css classes there is the same problem (when you have two similar classes). And this case is decided using css modules (set of rules of building) or you can use css-in-js (external library) which has its pros and cons. Also you can use BEM (methodology) and if your application is not big you can avoid this trouble.
css modules will add to your classes random hash and instead .my-awesome-class-name you will get .my-awesome-class-name-dew3sadf32s.
So, if you have two classes .class in the first file and .class in the second file in the end you will get two classes .class-dew23s2 and .class-dg22sf and you styles will resolve as expected.
css-in-js is a similar way except you should write your styles using javascript with some profits like including only those styles that are needed at the moment (what you are looking for right now) and several others.
You can code using pure css / scss / postcss / etc but many companies already choose between css modules and css-in-js.
BEM is just naming conventions for your class names.
And lastly - if you use inline-styles using react you should remember:
{} is constructor of object and {} returns new object on every call, it's mean if you write something like:
class MyAwesomeComponent extends Component {
render() {
return <div style={{color: "red"}}></div>;
}
}
or
class MyAwesomeComponent extends Component {
render() {
const divStyles = {color: "red"};
return <div style={divStyles}></div>;
}
}
div will re-render every time your render will call because div takes new prop.
Instead, you should define your styles (for example) in outside of your class:
const divStyles = {color: "red"};
class MyAwesomeComponent extends Component {
render() {
return <div style={divStyles}></div>;
}
}
Don't define your css using HTML tags because it will affect your entire application.
use className,id or inline styling.
like- App.css
.myApp{ color: red;}
#myApp2{ color: blue;}
App.js
import './App.css'
<div className="myApp">color changed by className</div>
<div id="myApp2">color changed by id</div>
<div style={{color:'red'}}>color changed by inline object styling</div> // inline styling
This is not the best solution if you are looking forward to improve yours css imports/loads.
However could be the best solution if you dont want to go in deep in css, resolve the problem fast and keep working with HTML tag.
You can add a div for each component, define an Id for the div and wrap the component. Afterwards in the component's css fies you are going to define all the styles starting with the #id so all the css classe or HTML tag will affect just the corresponding component.
//App render in root
ReactDOM.render(
<App />,
document.getElementById('root')
);
//App
function App(props){
return [
<Blog />, <OtherComponent />
]
}
//Blog component
function Blog(props){
return <div id="blog">
<h1>I am Blog</h1>
</div>
}
//Other component
function OtherComponent(props){
return <div id="otherComponent">
<h1>Im am other component</h1>
</div>
}
/* blog.css*/
#blog h1{
color:yellow;
}
/* otherComponent.css*/
#otherComponent h1{
color:green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Applying CSS stylesheet only to active component

I'm working on a ReactJS app that has a header at the top, a menu on the left, and the "frame" in the middle is where routes and their corresponding components are loaded. I want to be able to apply a CSS stylesheet to specific components only when they are loaded. I also don't want them applied all the time or to the top header or left menu.
My expectation was that adding import 'custom.css'; to a specific component would only apply the stylesheet's styles to that component and it's children when the route is active. Instead, it applies it to the entire page even when the route/component are not loaded.
I understand that an alternative approach is styled components, but, for my use-case, a design company is supplying a stylesheet (which should remain unchanged) that we need to consume only for the sub-module I'm working on and I don't want its styles to affect the rest of the app.
How can I have a stylesheet only applied to my active route/component?
Use simple CSS technique. Suppose you have two components with different css files (say about.css and contact.css). Now consider your both CSS file have one common class with different style properties, like:
about.css
.container{
max-width: 400px;
}
contact.css
.container{
max-width: 500px;
}
Yes in ReactJS both the CSS files will load at the same time and will override any one of the style. so to solve this problem add class to differentiate this styles, like:
about.css
.about-component.container{
max-width: 400px;
}
contact.css
.contact-component.container{
max-width: 500px;
}
If you want apply only when the component is mounted, you can use the lifecycle.
The follow example is based in the idea you are using sass, React, sass-node and have the loaders into webpack.
<pre>
import React from 'react';
import './styles.scss';
class MyComponent {
constructor(props) {
super(props);
this.state = { className: '' }
}
componentDidMount() {
this.setState({
className: 'myOwnClass'
});
}
render(){
return (
<div className={this.state.className}>This is a example</div>
);
}
}
export default myComponent;
</pre>
To be able to only call that specific CSS when you need it you can use CSS Modules. You may need to update your version of react.
When saving your CSS file save it with a ".module.css" eg. "styles.module.css". The CSS in these files can only be used and accessed by hte components where are they are imported. As stated in a tutorial from W3Schools.
Let's say this is your CSS code in styles.module.css:
.container {
color: white;
}
.cont-child {
background-color: red;
}
Then in your JS file you can import the CSS file like this if the JS and CSS files are in the same directory. Make sure you point to the correct path.
import styles from './styles.module.css'
Then in your HTML section you can use it like this:
class Home extends React.Component {
render() {
return(
<main className={ styles.container } >
<div className={ styles["cont-child"]} >
Some div text about something...
</div>
</main>
);
}
}
I currently use both ways to access the selectors, since the styles variable acts like an object. I placed both of them here because the second option is capable of fetching selectors named like "btn-active". Which comes in handy in some situations. Camelcasing is considered cleaner though.
Please note: I originally posted this answer as a reply to a similar question here React CSS - how to apply CSS to specific pages only
I want to be able to apply a CSS stylesheet to specific components
only when they are loaded.
Why not apply the styles inline via React.js?
Step 1. Create the style object for the component:
var componentOneStyle = {
color: 'white',
backgroundColor: 'red'
};
Step 2. Populate the component's style attribute with the style object:
ReactDOM.render(<div style={componentOneStyle}>This is Component One</div>, mountNode);

How use custom-style or shared styles in polymer 3 preview

I need to use common styles for app, but <custom-style> doesn't work. Attribute include in <style></style> doesn't work also. How do it?
EDIT: Alternative approach, use template literals.
I realized that there is, what I feel is a much better and more
natural alternative now that template literals is being used.
In shared-styles.js:
import { html } from #polymer/polymer/polymer-element.js;
export const sharedStyles = html`
<style>
... various styles here ...
</style>
`;
Now in the custom element file you want to use it ( my-element.js ):
import { PolymerElement, html } from #polymer/polymer/polymer-element.js;
import { sharedStyles } from './shared-styles.js';
class MyElement extends PolymerElement {
... element code ...
get template() {
return html`
${sharedStyles}
<style>
... your element custom styles here ...
</style>
`;
}
... rest of your element code ...
}
For me this makes far more sense because we are using native javascript and
avoid any extra polyfills that may be required by the include=""
functionality.
I also think this is a bit more future proof, since the include="" syntax
isn't really in the spec and I don't expect it will be? (Can anyone correct me
if I'm wrong on that?)
END (Alternative approach)
OLD Answer below
This has now been documented in the upgrade guide when 3.0 went live.
See the first section under "Less common upgrade tasks" on this page:
https://www.polymer-project.org/3.0/docs/upgrade
Also, remember that you would need to import custom-style into the js module before it will work.
Should be located here: polymer/lib/elements/custom-style.js
Had the same Problem, solved it by doing it manually:
const documentContainer = document.createElement('div');
documentContainer.setAttribute('style', 'display: none;');
documentContainer.innerHTML = `
<dom-module id="shared-styles">
<template>
<style>...</style>
</template>
</dom-module>`;
document.head.appendChild(documentContainer);
Then you can use it by simply importing and including.
import './shared-styles.js';
...
static get template() {
return `<style include="shared-styles"></style>...`;
}
I got this solution from the polymer-modulizer, but i hope there will be a better way in the future.
If we follow what polymer team has done already, then you need myapp-styles.js as below
import {html} from '#polymer/polymer/lib/utils/html-tag.js';
/*
custom classes for my application
*/
const template = html`
<dom-module id="myapp-styles">
<template>
<style>
.bold{
font-weight: bold;
}
</style>
</template>
</dom-module>
`;
template.setAttribute('style', 'display: none;');
document.head.appendChild(template.content);
Then in the component page you need to import 'myapp-styles.js'; and simply include it along with custom-style tag
<style is="custom-style" include="myapp-styles iron-flex iron-flex-alignment"></style>

Resources