Set the ClassName with state value in modular css in react - css

I am using modular css in react. I have to addClass to a <h2> how do I do that the problem is I am using modular css I know how to do it in normal css.Please Help.
Here is my component
import React, { Component } from 'react';
import style from '../css/MessageHeader.css';
class MessageHeader extends Component {
constructor(props) {
super(props);
this.state = {
name : "name"
}
}
render(){
return(
<div className={style.container}>
<div className={style.iconWrapper}>
<i className ="fas fa-angle-left"></i>
</div>
<div className={style.profileWrapper}>
<h2 className={this.state.name}>john appleseed </h2> //this is how I would in normal css
</div>
</div>
);
}
}
export default MessageHeader;

This would help you add the className this way. Variable is any variable in state with classname
<h2 className={`${this.state.variable}`}></h2>

While you can use a global class, I'm assuming you also want the h2 classes to be scoped to that component. Just like your other classes, you need to reference the style import - but use a dynamic key based on the state, like so:
<h2 className={style[this.state.name]}>john appleseed </h2>
Then your css module MessageHeader.css should contain a class for all names that you want to custom styling for.
Example:
.container {
// some styles here
}
.johnAppleseed {
color: yellow;
}
// You can also specify a name as a child of the container just like normal css,
// although it's not really necessary
.container .bobBobbert {
color: red;
}
Keep in mind that if your name in the state has spaces, that isn't going to work for a css class name, so you'll have to do some transformation (e.g. this.state.name.replace(...) to remove spaces and/or punctuation.

Related

How to extend styles in react component?

I have a task when I need to extend the styles of a certain element. I take the basic styles through the module, and the additional ones will need to be done inside the function that will be in the component.
How can I extend the styles inside the component if I have already added styles from the module there?
import style from './styles.module.css';
const optionalStyles = {
margin: "30px"
}
<p className={`${style.subtitle} ${optionalStyles}`}>42</p>
<p style={optionalStyles} className={`${style.subtitle}`}>42</p>
You can:
Create another class inside your styles.module (or any other module) and add it conditionally:
import style from './styles.module.css';
<p className={`${style.subtitle} ${someCondition ? style.otherStyles : ''}`}>42</p>
Use inline styles:
import style from './styles.module.css';
const optionalStyles = {
margin: "30px"
}
<p className={style.subtitle} style={someCondition ? optionalStyles : {}}>42</p>

How to use nested css class (cascade) with React CSS Modules

I did see a lot of similar questions on SO but at end, it seems that my issue is a bit different..
I have a react project where (for some reason) I want two types of CSS loading:
Some global (imported from main.tsx as import 'assets/global.css';)
Some scoped (imported from a component as import style from './style.module.css';)
The global ones works as expected, it's the module one that are weird.. If I want to style a simple <a></a> within a div, this following works:
copyrights
.copyrights a { // as Link is rendered as a `<a></a>`
text-decoration: none;
}
/*...*/
import style from './style.module.css';
export const CopyrightsComponent = () => {
return (
<Container className={style.copyrights}>
<Row className={`justify-content-center`}>
<p>
{COPYRIGHTS_TEXT}
<Link to={TERMS_OF_USE_ROUTE_ROUTE}>{COPYRIGHTS_TERMS_OF_USE_HYPERLINK}</Link>
<Link to={TERMS_OF_USE_ROUTE_ROUTE}>{COPYRIGHTS_PRIVACY_POLICIES_HYPERLINK}</Link>
</p>
</Row>
</Container>
);
};
export default CopyrightsComponent;
HOWEVER! When trying to nest CSS in order to select the right child (like a specific img within a certain div), it doesn't work.. I don't understand why
foo
.foo .bar1 a {
text-decoration: none;
}
.foo .bar2 a {
color: red;
}
/*...*/
import style from './style.module.css';
export const FooComponent = () => {
return (
<div className{style.foo}>
<div className{style.bar1}>
<a>bar 1</a>
</div>
<div className{style.bar2}>
<a>bar 2</a>
</div>
</div>
);
};
export default FooComponent;
Thanks for any help...
This doesen't work since your .bar class is scoped to the element.
It should work, if you reduce the specificity of the selector to either:
.foo div a
or,
.bar a
When you utilize CSS modules, and you link your class directly to an element - the class name becomes unique, since obfuscation is appended to the class name, as per the CSS modules spec (It is scoped to the element). You can see this by inspecting a DOM element that you have linked to a class with this technique; It looks something like this: component_name-module--class_name--eq-vo.
Because of this, when you try to chain custom selectors like you did originally, the middle part of the selector (.bar) doesen't exist in its original simplicity because of this obfuscation.

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>

Angular/CSS Style parts of a component dynamically

I have a component, that has different parts. However, I want to be able to style the individual components with different colors.
For instance:
<div class="OuterBox">
<div class="InnerBox1"></div>
<div class="Seperator"></div>
<div class="SecondBox">
<div class="TextInfo"></div>
</div>
</div>
I add this to a page, via a standard Angular component:
<app-my-component></app-my-component>
I have seen the ngStyle option for Angular which I could use to specify , but my problem is I cannot simply do a <app-my-component [styles]="{backgroundColor: 'blue', 'font-size': '16px'}">. I need to color the different div sections differently, for instance the InnerBox1 has a background of green, and the SecondBox background should be red.
I can do these styles on the individual CSS, but when I want to make this a common component, I want to be able to change the colors on each instance, so they can be different from green and red, and could be blue and orange or something else.
You can simply declare a variable for each color in your component and bind them from outside
In your component :
import { Component, Input } from '#angular/core';
#Component({
selector: 'app-my-component',
template: `<div class="OuterBox" [ngStyle]="{backgroundColor: outerBoxColor}">
<div class="InnerBox1"></div>
<div class="Seperator"></div>
<div class="SecondBox">
<div class="TextInfo"></div>
</div>
</div>`
})
export class MyComponent {
#Input() outerBoxColor;
}
and then pass the color from outside like this:
<app-my-component [outerBoxColor]="'blue'"></app-my-component>
<app-my-component [outerBoxColor]="'red'"></app-my-component>
Or if you want style more than just one css selector you can use DomSantizer and pass all css style to your Child component
In parent:
<child-component
div1Style='width: 400px;background-color:red;'
div2Style='width: 400px;background-color:red;'>
</child-component>
child component input variable:
#Input() div1Style: string;
#Input() div2Style: string;
in child in html div
<div [style]='GetStyle(div1Style)' >
<div [style]='GetStyle(div2Style)' >
and in code of child component
constructor(private sanitizer: DomSanitizer) { } //to inject instance of this DomSantizer
GetStyle(c) {
if (isNullOrUndefined(c)) { return c; }
return this.sanitizer.bypassSecurityTrustStyle(c);
}
and you can declare as many these variables as you need - one per each div for example

How to limit style to component level in React?

My app tries to show emails. Sometimes the style in the email will affect the app itself.
Right now I am using the package juice to inline style in the email html. However, sometimes it cannot inline correctly. So I try to find other solutions.
I know Angular automatically add some random string in each class to make sure style in one component won't affect other component, is there a same way to do it in React? Or is there other way to limit style to the component level without using iframe? Thanks
The demo shows the p { color: red; } from the email also affects the app itself. In this case, it affects Content in app.
Live demo
class Mail extends Component {
render() {
// the style inside is from mail, in real case, it can have tens or even hundreds of different styles
const mailFromServer = `
<html>
<head>
<style>
p { color: red; }
</style>
</head>
<body>
<p>Content in mail</p>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mailFromServer}} />
</div>
);
}
}
class App extends Component {
render() {
return (
<div>
<Mail />
<p>Content in app</p>
</div>
);
}
}
There are few ways to do this.One of the way would be by passing style to the elements and defining styles as objects. For example
const styles = {
content: {
color: '#000',
backgroundColor: '#fafafa',
},
};
class Mail extends React.Component {
render() {
return() {
<p style={{styles.content}}> Content </p>
}
}
}
If you really want something scalable then you can use styled-components which for me personally work really nicely and fulfills all your styling needs.
You'll need to use a class to limit the style to a specific component's features:
import React, { Component } from 'react';
import { render } from 'react-dom';
class Mail extends Component {
render() {
const mail = `
<html>
<head>
<style>
.mail-header { color: red; }
</style>
</head>
<body>
<h1 class="mail-header">Heading in mail</h1>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mail}} />
</div>
);
}
}
export default Mail;
Styles in <style>..</style> or from CSS sheet is global. They are applied across your app.
If you have control over how the email is formatted, I would recommend setting different class names for different email types.
If you have a limited set of email types, you can specify the styles for each of them in a css sheet, and import it on your html file or Webpack.
styles.css
.important-email { color: red; }
.not-important-email { color: blue; }
// ...
// styles for different email types
Mail.jsx
class Mail extends Component {
render() {
const mail = `
<html>
<head>
</head>
<body>
<h1 class="important-email">Heading in mail</h1>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mail}} />
</div>
);
}
}
export default Mail;
Yes, you can use CSS Modules, which is one or more css files (written in js) in which all class names are auto-scoped locally to each component by default.
There is a good article about this here https://medium.com/#pioul/modular-css-with-react-61638ae9ea3e
You can also try to reset those known html entities which are commonly over-ridden by your Mail html. You may have to play around a bit, but, given your example, you could do something like the following:
https://stackblitz.com/edit/react-neymbb
Basically, in my sandbox I reset your paragraph color and padding to their defaults, as well as, used it in conjunction with another inline style. Depending on the entire construct of css inheritance in your app, your results may vary, but you should be able to get something workable.
More information on the css values I recommend found here:
https://developer.mozilla.org/en-US/docs/Web/CSS/initial

Resources