React imports CSS from other components - html

I am having a problem with CSS imports in React, I have a page Home that imports Home.css and a page Hero that imports Hero.css appearently in every page of the application the Hero.css is being applied without even declaring it how can I fix this? These are the following components:
App:
import './App.css';
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Home from './pages/home/Home';
import Hero from './pages/hero/Hero';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />}></Route>
<Route path="/hero" element={<Hero />} ></Route>
</Routes>
</Router>
);
}
export default App;
Hero:
import './Hero.css';
function Hero() {
return <div>
<h1>Hero!</h1>
<button className='glow-on-hover' disabled>test 1</button>
<button className='small-button glow-on-hover'>test 2</button>
<button className='small-button glow-on-hover'>test 3</button>
</div>;
}
export default Hero;
Hero.css:
div {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
justify-items: center;
background-color: #002bff;
}
Home:
import './Home.css';
function Home() {
return <div>
<p>Home!</p>
</div>;
}
export default Home;
The div in the Home component is blue even though the Home.module.css is empty and I declared that the div must be blue only in the Hero.module.css how can I fix this?

First, it's important to understand that importing CSS into a JS page is not actually a feature that JavaScript has. It's an instruction to a bundler like Webpack to include this CSS in the build process.
Moreover, CSS has no native means of scoping it's effects to a cetain component. It's your responsibility to apply the scoping via a class etc.
For example:
React
return <div className="component-hero">
...
CSS
.component-hero {
...
}
Edit:
While the information above is indeed the nature of CSS, there are apparently available tools for automating the scoping with unique identifiers. See references in other answers.

Since there is no built-in scoping mechanism to limit CSS Rules to specific components, This behavior is completely normal, Which results in all your div elements in the component tree to be effected by this import.
I would recommend using CSS Classes to have a layer of scope at least semantically.
<div className="hero-container">
// nested jsx...
</div>
And then add CSS rules in your hero.css file:
.hero-container {
// css-rules
}
create-react-app toolchain has a concept called CSS Modules, If you happen to be using this toolchain, checkout official documentation of CSS Modules here.
Since all our CSS is bundled into a single index.css file at the end of the day, It's harder to maintain distinct class names in larger projects. So, it's better to use a more elegant solution like CSS Modules or third-party libraries that style our components in a tightly coupled fashion, like styled-components etc.

That because you apply the CSS as global.when you are importing in css like import './Home.css';.So it is apply as global. If you need to apply CSS styles as scope to component, you can use different options as below.
One option.
you can use module.css file. According to the official repo.“CSS files in which all class names and animation names are scoped locally by default”.In here you are you can declare styles using classes. but this is not supported to css id.so always to remember declare classes inside the module.css file.
let's deeper in to this.
let say I have declare home.module.css file as this.
.home{
background:green
}
then you cam import this to your jsx file as below and apply this class as below.
import homeStyles from './home.module.css';
export const Home= () => {
return (
<section className={homeStyles.home}>
module.css example
</section>
);
};
when looking at the code you can get idea that I have declared variable by this line," import homeStyles from './home.module.css';".and I am accessing that class inside the section div using homeStyles.home.That because homeStyles is a object that contain the home class property.
Second Option
You can use Styled components. See official doc.This is a third party library. but has much resources to adding and modifying the styles. if you are use, Maetrial ui V5 It also used the this styled component styling pattern.(Just check material ui v5 Styled hook).This styling pattern is not used in the previous material ui versions. The One important this is we can use css classes and css ids for styles the our react elements.
Let say we need to style div with class home which has css propety to background green. we can style this as below.
import styled from "styled-components";
const sectionWrapper = styled.div`
.home {
background: green;
}
#media screen and (max-width: 600px) {
.home {
background: red;
}
}
`;
export const Home = () => {
return (
<sectionWrapper>
<div className="home">module.css example</div>
</sectionWrapper>
);
};
As in the module.css file, we can use media queries in the styled component as well. I have add a media query in the example as well. It explain s that screen size less than 600px,that home class div make background red. You can get better idea about this from their official site. see

Related

CSS of one component causing unwanted formatting in another

I am still just learning in Angular, CSS, and HTML (all three are new), so have some patience with me please.
I received some code, and was given the task to fix some formatting.
Here is the problem:
When the page first loads, the page header has some padding. See picture below on the left.
However, when I navigate to another page, which has this code:
/* Removing padding and scroll bar from main page */
::ng-deep html > body > main#app-content {
overflow-y: hidden;
padding: 0;
}
and then navigate to any other component/page, the padding is gone and everything is moved all the way to left of the screen, which is very annoying. See picture below on the right. Note: someone told me that this is the code that is causing this situation, and I actually have no idea what it is actually doing (besides setting the padding and y-scroll).
This picture shows two components/pages before I access the page with the code above (shown on the left side in the picture), and then after I navigate to that page with the code above (shown on t eh right side in the picture). Note the green line is for reference to show how the padding is gone.
So I would like to have the original padding/formatting back when I navigate back to it after I access the page with the code above.
Also, can someone explain to me why it's doing this? And if possible, what does the code actually mean? Here are some specific questions:
How can I stop this from happening on another page?
What does "::ng-deep html > body > main#app-content" mean?
What does the greater sign do?
TLDR: Here is a stackblitz with an example of how to edit a global style using a service rather than ::ng-deep. https://stackblitz.com/edit/angular-ivy-p4pkdu?file=src/app/app.component.html
::ng-deep is an angular feature that promotes the following css to apply globally (everywhere in your application). It should really be avoided, as there is usually a better way to apply global styles. This feature is actually being deprecated, I'll put an alternative at the end of this answer.
html > body > main#app-content is just a CSS selector. In this case we are selecting the main element with id app-content, which has body as a parent, which has html as a parent. Here is a good reference for CSS syntax: https://www.w3schools.com/cssref/css_selectors.asp.
So we are applying these css styles to an html element of type main and with id app-content, the style is applied globally, so it will still persist after the encapsulating component is destroyed.
A better alternative to ::ng-deep is to use a service to edit global styles. First off, any global styles should be stored or imported into the global styles file, usually called styles.css in an angular project. If you only need the style in one component, you can put this css in the respective component css file instead. We declare it as a class so we can add it to an element dynamically.
In styles.css
.noPaddingOrScrollbar {
overflow-y: hidden;
padding: 0;
}
Then generate a service with the cli using ng g service <serviceName>. For example, to generate a service named globalStyleService in a folder called services we do ng g service services/global-style. We'll add a boolean to our service to indicate whether we want the style applied or not.
One caveat is that we need to use setTimeout to set the boolean, to avoid the dreaded NG0100: Expression has changed after it was checked error. setTimeout will default to a timeout of zero, but will still delay the code execution until after Angular finishes a round of change detection.
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class GlobalStyleService {
private _noPaddingOrScrollbar = false;
set noPaddingOrScrollbar(value: boolean) {
//Delay setting until after change detection finishes
setTimeout(() => (this._noPaddingOrScrollbar = value));
}
get noPaddingOrScrollbar() {
return this._noPaddingOrScrollbar;
}
constructor() {}
}
Now you need to find in what component this main#app-content element is actually located. It'll be in the html file of one of the parent components. You can then inject the service into this parent component ts file, and set the class dynamically in the component's html file.
Parent component ts file
export class ParentComponent {
constructor(public globalStyle: GlobalStyleService) {}
...
}
We use the angular directive [class.className]="boolean" to set the class dynamically.
Parent component html file
...
<main
id="app-content"
[class.noPaddingOrScrollbar]="globalStyle.noPaddingOrScrollbar"
></main>
...
Now you can add or remove this class from anywhere in your application. So in the component containing the hacky css, we inject the service, add the style during ngOnInit and remove it during ngOnDestroy. Of course remove the ::ng-deep statement from the css file as well.
Child component ts file
export class MyComponent implements OnInit, OnDestroy {
constructor(private globalStyle: GlobalStyleService) {}
ngOnInit(): void {
this.globalStyle.noPaddingOrScrollbar = true;
}
ngOnDestroy(): void {
this.globalStyle.noPaddingOrScrollbar = false;
}
...
}

How to apply styles to the HTML in Next.js at server side render?

Visit Next.js and notice the page request in the network tab. Preview shows not just the HTML but completely pre-styled page.
When we use Styled-Components and Material-UI they have exposed ServerStyleSheet which is used for serving the required styles for the first render within the HTML.
import { ServerStyleSheet } from 'styled-components'
import { ServerStyleSheets } from '#material-ui/core/styles'
How can we achieve same output when using react-bootstrap or custom css like test.css?
Do you care if its a test.css or React bootstrap - Instead why not just inline all critical stylesheets?
It might be worth trying out their experimental feature
Add experimental: { optimizeCss: true } to next.config.js
Install critters#0.0.7 as a dependency
Via How to inline CSS in the head tag of a NextJS project?
Add your style file on the the _app file, you can create this file inside the pages directory in nextjs
import { AppProps } from "next/app";
import 'bootstrap/dist/css/bootstrap.min.css';
import "../your_style.css";
function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}
export default App;
for react-bootstrap , you need to add npm i react-bootstrap bootstrap
Nextjs allows you to display SSG/SSR pages and javascript-disabled
users will still be able to see your app but the layout will be messy
if you use react-bootstrap components to build your layout.
To use react-bootstrap at SSR:
Install :
npm i react-bootstrap bootstrap
Import bootstrap styles in your _app.js:
import 'bootstrap/dist/css/bootstrap.min.css';
You can then use your react-bootstrap components as you would do in reactjs:
import {Container, Row, Col} from 'react-bootstrap';
const Layout = () => (
<>
<Container fluid>
<Row>
<Col>
<p>Running on Next.js at SSR</p>
</Col>
</Row>
</Container>
</>
);
export default Layout;
use Tailwind css
https://tailwindcss.com/
We can simply use classes and it make everything super easy for you design

Overriding PrimeReact Styling

I am trying to find the best solution for overriding the default 'Nova' theme used for Prime React. I am aware they have a theme designer available to purchase however I would ideally like to not use that.
Previously I was having a scss file with every tsx file in my react application. I was using lines such as -
.p-dropdown-trigger {
background-color: brown !important;
margin-left: 5px !important;
}
I was basically putting !important everywhere and it began to get very messy.
I have thought about commenting out the import for the Prime React theme in my index.tsx file
// import 'primereact/resources/themes/nova/theme.css';
And importing my own scss instead..
import './styles/Override.scss';
This makes the styling disappear completely and the page looks like it's purely html. I am thinking maybe I should copy all the code from the Nova theme file and then slowly start adjusting it in the override file.
Has anyone got a better way or any ideas?
Thanks
One option like you said is to copy all of the css over, and then hide their import. That may be more work than you need depending on what you're trying to do.
I would probably rather create an override.scss and specifically overwrite rules, which with scss nesting shouldn't get too crazy. But one tip to avoid using !important is to be more specific with the way you target HTML elements. For instance, if there is a CSS rule of
body header ul a { color: pink; }
then you can override a rule by being more specific and write:
body header ul li > a { color: blue; }
However if the rule you're trying to overwrite has !important in it, then you'll have to use !important in your new rule overwrite it.
Hmm, maybe I could help more if I had access to more code e.g. in codesandbox.io.
Do you try some modular CSS solution? Like Styled-jsx or Styled-Components?
If you would like to use styled-components, this answer could be helpful. PrimeReact and styled-component
A different solution could be, link the stylesheet with PrimeReact before your own stylesheet (inside of your HTML). This solution will require a deep analysis of the style implementation by the webpack.
Hope I could help somehow :)
Later CSS imports that come after the theme will override the templates as the last CSS rule has higher specificity (precedence) in CSS
In the following of a create-react-app index.tsx (typescript .js), index.css will override the imported prime themes but CSS imports in the child React "App" component will not override the theme because it is imported first. (And the last applicable CSS is the one that gets used unless you override with !important.)
import React from "react";
import ReactDOM from "react-dom";
import reportWebVitals from "./reportWebVitals";
import App from "./App";
import "../node_modules/primereact/resources/themes/saga-blue/theme.css";
import "../node_modules/primereact/resources/primereact.min.css";
import "../node_modules/primeicons/primeicons.css";
import "./index.css";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
You can make your React component's CSS (like "App") override the React Prime theming by importing the theme CSS as the first thing, then components after making their CSS later and higher precedence.
import "../node_modules/primereact/resources/themes/saga-blue/theme.css";
import "../node_modules/primereact/resources/primereact.min.css";
import "../node_modules/primeicons/primeicons.css";
import React from "react";
import ReactDOM from "react-dom";
import reportWebVitals from "./reportWebVitals";
import App from "./App";
import "./index.css";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);

Use styling for ng-content from template component

I've created a template case component which I'm intending to use for multiple cases. To use the component as a template, I used ng-content select="".
It works fine, but not completely as desired. For example:
I have a div with a background image, its style is being configured inside of the template component:
<div class="front-image min-vh-100 min-vw-100" [style.transform]="'scale(' + scale + ')'">
</div>
To make this usable as a template, I replaced the given code with: <ng-content select=".front-image"></ng-content> and used the template inside of another component like this:
<app-case-template *ngIf="cases[3] as case">
<div class="front-image min-vh-100 min-vw-100" [ngStyle]="{ 'background-image': 'url(' + case.image + ')'}"
[style.transform]="'scale(' + scale + ')'">
</div>
</app-case-template>
How can I achieve the template to always get its styling from the template component - right now I had to declare its styling inside of the new component to get it working. Additionally [style.transform] stopped working.
Is there something like a bypass?
You may be going about this the wrong way. I'll try to outline a good way to do it. First, have a directory for your templates:
templates
- template.component.css (generic styling)
- template.component.html (your markup)
- template.component.ts (your ts/js)
Set up your template.ts for use:
import {Component} from '#angular/core';
#Component({
selector: 'template-component',
templateUrl: 'template.component.html'
styleUrls: ['./template.component.css']
})
export class TemplateComponent {
}
Register it in your component.module.ts (or whatever you may have called it):
...
import {TemplateComonent} from './templates/template.component';
...
const exportedComponents = [
SvgIconComponent
]
If needed, have your shared.module.ts export it:
import {ComponentsModule} from './components/components.module';
...
exports: [ComponentsModule]
Now you can use it like it's a custom HTML tag (your selector):
<template-component class="template"> </template-component>
Now it will always grab the css styling from itself, but you can stick a custom class in that tag as I have done, or call it like this from your main component's style page:
template-component {
margin: 10px;
background-color: grey;
}
There's a lot you can do including setting #Input() tags in your template that can be called from your HTML tag. You can also use Angular bindings to dynamically enter values or text into it. Many options here.
Note: instead of calling them templates, consider calling them shared components, or shared modals (if so). Have a directory called shared > components and have a custom-name directory with the like in there for organization.

Enabling CSS modules in ReactJS by adding a .module to CSS file name

I am new to ReactJS , I was reading about how to enable CSS modules and what i came to is:
If you add .module it will add a base64 hash string to the name of classes used
Actually i created a function-based component Layout.js
import React from "react";
import classes from "./Layout.module.css";
const layout = props => <div className={classes.bg}>Here first div</div>
export default layout;
and css file as Layout.module.css
.bg {
display: inline;
background-color: rgba(115, 251, 4, 0.685);
}
When i inspected the div in browser:
<div class="Layout_bg__1bzIA">Here first div</div>
everything seems to work fine, But when i created another component second.js with a div in it and applied the same class
import React from "react";
import classes from "../Layout/Layout.module.css";
const second = props => <div className={classes.bg}>Here second div</div>
export default second;
And when i inspected the second div it looks like:
<div class="Layout_bg__1bzIA">Here seond div</div>
They both took the same hash value, So my question is it right what i quoted above
.module enables CSS modules
And if it is , Why it gives the same hash values to different elements in different components
In my understanding module allows you to create same classes name without mixing them together. I mean by it that when you create another module with the same class name (in your case bg) it will have assigned different hash value which means they will have different names and therefore those two classes will never mix together.
Hope that helps.