React css formatting conditional on ant component - css

I am trying to send in a style property to a component and not sure what the difference is..
Why does this statement work and applies the formatting
<Toggle
className={styles.toggle_show} // class name gets passed as Map_toggle_show__17ukO and applied
/>
but this statement throws errors
<Toggle
className={isShow ? {styles.toggle_show} : {styles.toggle_hide}}
/>
If I update the second statement to
<Toggle
className={isShow ? "styles.toggle_show" : "styles.toggle_hide"}
/>
The classNames do get passed to the component but css dont get applied.
Also why is this message coming on the const declaration
import styles from "./Map.module.scss";
const [ToggleVisibilyClass, setToggleVisibilyClass] = React.useState(
{styles.toggle_show}
);
(property) styles: {
readonly [key: string]: string;
}
Parsing error: ',' expected.eslint

Try this:
className={isShow ? styles.toggle_show : styles.toggle_hide}

The correct way in your case will look like this:
<Toggle
className={isShow ? styles.toggle_show : styles.toggle_hide}
/>
styles is actually an object with string properties, so {styles.toggle_show} is not valid syntax, that's why you are getting an error.
And this "styles.toggle_show" is working because it's a string, but it's not the correct string. Behind the scenes Webpack generates a different name for your classes, usually a unique one and you can access it with styles.toggle_show.
Also if you have some more complicated scenarios try using the classnames package it can make things easier and it have a lot of examples.

Related

inline style vs className in Componet context

Hello I try to understand when it's necessary to use inline style instead className in this case. I take a long time to solve my problem of translation. At the beginning I want to translate component by using classNameand that's don't work. it's very weird because in my point of view there is no reason that's happen. So I figure there is something wrong in my code, but what... I have not yet found. So I finish trying to translate by using a inline style. Miracle, that's work fine.
My question is why ?
Work well
export function Content() {
return (
<div style={{transform: 'translateY(100px)'}}>
<Test/>
<Footer />
</div>)
}
don't work
export function Content() {
return (
<div className={container_content}>
<Test/>
<Footer />
</div>
)
}
css
.container_content {
transform: translateY(100px);
}
Nota bene :
The problem is not from the method. To use className in my jsx
must be like that:
import { container_content } from "./test.module.css";
and next
<div className={container_content}><div>
So this part of code is good, the issue seems to come from elsewhere...
What's happening is that when you use the inline style you are passing an object that includes the styling for that component. When you use the className you need to pass in a string for the class you want to use. Right now you are passing a variable name. Either of these works:
<div className={"container_content"}>
OR
<div className="container_content">
If you think about it in regular html you would do
<div class="container_content">
EDIT: Given your updated question, you should just import the css file with:
import "./test.module.css"
and then use the solution I mentioned.
inside the js file, you need to import the CSS file like this
import " css-file-dir";
and then you can Reference to the CSS classes inside your component as a string
example :
className="container_content"

Css module in ReactJS, using in ternary operators syntax

I have a useState and try to render my Modal windows based on it.
Here is my code and I used css modules for my classes.
The thing is I am not able to find the correct syntax to doing so.
I ended up writing this but it does not work.
export default function Modal({ content }) {
const [showModal, setShowModal] = useState(true);
return (
<div className={`${showModal} ? ${styles.ModalWindow} : ${styles.DisplayNone}`} </div>
The backtick (`) symbol indicates a template literal/string in JavaScript. You would only want to use this feature if you want the class to literally be something like "condition ? window-class : hidden".
In this case, you want the expression to be evaluated, not converted into a string literal. So just get rid of those template literal markers:
<div className={showModal ? styles.ModalWindow : styles.DisplayNone} </div>

Can't bind since it isn't a known property of angular component

I am trying to conditionally set a classname based on a boolean variable. I have set the variable within the parent component:
public alteredSidebar: boolean;
And this is my though process behind conditionally defining which class it is:
<div [class]="alteredSidebar == false ? 'secondsidenav' : 'sidenav'" id="rollup-sidenav" [ngClass]="{ 'greyout': greyOut }"></div>
I have defined 2 classes with css file, one called secondsidenav and another called sidenav. Wherever I set the boolean as false, I would like the classname to equal the secondsidenav and where it is not false it be sidenav. Here is an instance of where I am using it and I am expecting the class to be set to 'secondsidenav':
<app-rollup [data]="rollupData" (resetCalled)="onRollupReset()" (entrySelected)="onRollupSelectEvent($event)" [alteredSidebar]="false">
</app-rollup>
However I am getting the following error: "Can't bind to 'alteredSidebar' since it isn't a known property of 'app-rollup'."
use #Input() decorator on it
#Input()
public alteredSidebar: boolean;
As #junk said, you should use the #Input() decorator in the app-rollup component and I'd like to add, do not mix [className] with ngClass, this might not be related to your problem but it gets really buggy if you're using a reactive property to programatically add or remove a class, just pick one and try not to mix them it will also make the code more consistent. Oh, and the correct syntax is [className] you're probably confusing it with [class.foo]="expresion" which will apply the 'foo' class if the expression is true
Personally I'd do something like this, also sticking with one approach is considered a best practice
<div id="rollup-sidenav" [ngClass]="{
'greyout': greyOut,
'secondsidenav': !alteredSidebar,
'sidenav': alteredSidebar
}">
</div>
Hope that helps, let me know if it doesn't!
#Berheet.. try this
assign the value alteredSidebar in the component itself and pass it like below
parentComponent.ts
public alteredSidebar: boolean = false;
parentComponent.html
<app-rollup [data]="rollupData" (resetCalled)="onRollupReset()" (entrySelected)="onRollupSelectEvent($event)" [alteredSidebar]="alteredSidebar">
</app-rollup>
Add Input in child component
childComponent.ts
#Input() alteredSidebar: boolean;
childComponent.html
<div [class]="alteredSidebar == false ? 'secondsidenav' : 'sidenav'" id="rollup-sidenav" [ngClass]="{ 'greyout': greyOut }"></div>
I'd suggest to simply set the div-tags class property conditionally as follows
[class]="alteredSidebar ? 'sidenav' : 'secondsidenav'"
This way you get a more readable condition ? positive case : negative case flow and you don't need to compare your variable to anything.

Is it possible to apply dynamic style as string in Angular?

I have a <span> that I want to apply dynamic style to.
Style is stored in a css-like string variable and can be arbitrary e.g.
myStyle = 'color: white; font-weight: bold;'
or
myStyle = 'background-color: red;'
I expected it to work like
<span style="{{myStyle}}">
but it didn't.
I tried different options but none seem to work for me for different reasons:
I can't put styles in a .css file and use class names because style is coming from server in the form of aforementioned string
Using [style.color] etc. doesn't suit me because I don't know what the style can be
Using [ngStyle] doesn't suit me because it expects object like {'color': 'red', 'font-weight': 'bold'} and I only have string
The reason I have a style stored in a string is because I need to apply it in HTML generated on the server where I simply pass that string to a placeholder variable in a velocity template.
I am almost confident that it can't be done the way I want but probably I am overlooking some solution.
All you need is DomSanitizer and bypassSecurityTrustStyle
Component side :
import { DomSanitizer } from '#angular/platform-browser';
constructor(private doms : DomSanitizer) {}
newStyle = 'background-color:red';
safeCss(style) {
return this.doms.bypassSecurityTrustStyle(style);
}
Template side :
<p [style]="safeCss(this.newStyle)">
Start editing to see some magic happen :)
</p>
WORKING DEMO
Angular provides the DomSanitizer service which can convert strings into style objects. I think this is exactly your case.
constructor(private sanitizer: DomSanitizer) {
}
sanitizeStyle() {
return this.sanitizer.bypassSecurityTrustStyle('background-color: red');
}
<span [style]="sanitizeStyle()">
I think I will go the way of converting the incoming css string into a style object and then applying it to <span> using [ngStyle]

Multiple classNames with CSS Modules and React

I'm using the following code to dynamically set a className in a React component based upon a boolean from props:
<div className={this.props.menuOpen ? 'inactive' : 'active'}>
...
</div>
However, I'm also using CSS Modules, so now I need to set the className to:
import styles from './styles.css';
<div className={styles.sideMenu}>
...
</div>
I'm having trouble with this - I tried using classnames to gain more control with multiple classes, but because I need the end result to be that the className is set to both styles.sideMenu AND styles.active (in order for CSS Modules to kick in) I'm unsure how to handle this.
Any guidance is greatly appreciated.
Using classnames and es6:
let classNames = classnames(styles.sideMenu, { [styles.active]: this.props.menuOpen });
Using classnames and es5:
var classNames = classnames(styles.sideMenu, this.props.menuOpen ? styles.active : '');
Bit late to the party here, but using string templates works for me - you could move the ternary operator out to a const if you'd like as well:
<div className={`${styles.sideMenu} ${this.props.menuOpen ? styles.inactive : styles.active}`>
...
</div>
I wanted to just add on a better way of using the bind api of classnames npm. You can bind the classnames to the styles object imported from css like below:
import classNames from 'classnames/bind';
import styles from './index.css';
let cx = classNames.bind(styles);
and use it like this:
cx("sideMenu", "active": isOpen)
where sideMenu and active are in styles object.
Using logical AND instead of ternary operator makes it even less verbose since classnames omits a falsy value.
<div className={ classNames(styles.sideMenu, this.props.menuOpen && styles.active) }></div>
This is the closest I can get to a working solution:
const isActive = this.props.menuOpen ? styles.inactive : styles.active;
<div className={isActive + ' ' + styles.sideMenu}>
This does work - both allow the styles in the imported stylesheet to be used, and is only applied when this.props.menuOpen is true.
However, it's pretty hacky - I'd love to see a better solution if anyone has any ideas.
Using Array.join
<div className={[styles.sideMenu, this.props.menuOpen ? styles.show : styles.hide].join(' ')}></div>
While I'm not an expert on CSS modules, I did find this documentation: https://github.com/css-modules/css-modules/blob/master/docs/import-multiple-css-modules.md
It appears that you'll need to combine the styles for active and sideMenu together using Object.assign
import classNames from 'classnames/bind'.
then you can use like this:
let cx = classNames.bind(styles);
In case like that styles['bar-item-active'] , you can wrap it . in second square brackets like [styles['bar-item-active']] : your condition
I don't think anyone has suggested using both the style and the className attributes in your React DOM element:
const sideMenu={backgroundColour:'blue',
border:'1px black solid'}
return <>
<div style={sideMenu} className={this.props.menuOpen ? styles.inactive : styles.active}>
...
</div>
</>
It's not the neatest solution, but it does avoid adding another dependency to your project and if your sideMenu class is small then it could be a option
Using classnames library
import classNames from "classnames";
classNames is a function. if you pass some strings, it joins them together if they all are truthy. If there is any falsy string it will not pass it. For example
let textColor=undefined
classNames(textColor, "px-2","py-2" )
since textColor variable is falsy, classNames will ignore it and returns this string
"px-2 py-2"
You can also pass an object to classNames function.
const active=true
const foo=false
Let's say I have this expression
classNames({
'text-green':active,
'text-yellow':foo
})
classNames function will look at "VALUE" of each pair. if the "value" is truthy, it will take the "KEY" but if the "VALUE" is falsy it will ignore the "KEY". In this example since "active" true and "foo" is false it will return this string
'text-green'
In your example, you want to add a className based on if the prop is truth or falsy in other words if the prop exists or not:
let classNames=classNames(
styles.sideMenu,
// based on props that you are passing you can define dynamic classnames in your component
{
"active":this.props.menuOpen
}
)

Resources