How to interpolate styles in React? - reactjs

I want to color-code words by language in my React app. I have a styles file, which contains things like:
english: {
// style here
}
french: {
// style here
}
spanish: {
// style here
}
// etc.
Each of my words (entrys) is an object that contains a language key/value pair, i.e. {language: french}.
I could create a long case/switch statement, but I'm looking for a shorter way. Here's my case/switch statement:
var color;
switch (entry.language) {
case 'english':
color = styles.english;
break;
case 'french':
color = styles.french;
break;
// etc.
<div style={color}> {entry.word} </div>
That seems unnecessarily repetitive, especially if I have a lot of languages. Instead, I want to be able to just interpolate entry.language into my div, something like:
<div style={styles.{entry.language}} {entry.word} </div>
That doesn't work. Is there a way to do it?

What you want is to access an object. The bracket notation is what you need
<div style={styles[entry.language]} >{entry.word} </div>

I stumble on this page with a similar question but ended up finding the answer
from https://medium.com/capital-one-developers/cut-the-sass-how-to-use-inline-javascript-styles-for-everything-f5ac5b77ae57
import React from 'react';
import { StyleSheet, css } from 'aphrodite';
import { brandRed } from './colors';
const styles = StyleSheet.create({
foo: {
border: `1px solid ${brandRed}`,
},
});
const UserMenu = () => (
<div className={css(style.foo)}>
This box has a nice border.
</div>
);

Related

How can i dynamically change images as Background in TailwindCSS?

I want to make a carousel, where the background is changing, i don't want to use the <img/> tag! I set the value as described in the documentation: https://tailwindcss.com/docs/background-image#arbitrary-values
My Code:
import React from 'react';
type CarouselProps = {
img: string;
};
const Carousel = ({ img }: CarouselProps) => {
return (
<div
className={`col-span-full bg-[url(${img})] bg-cover grid grid-cols-12 gap-6`}
> ...
</div>
);
};
When i set the String i pass to the Component hardcoded it works but when i use curly Braces and $ it doesn't. In addition i don't want to define my Background-Images in the tailwind.conf.js
The Error:
ERROR in ./src/index.css (./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[5]
.use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[5].use[2]!
./node_modules/source-map-loader/dist/cjs.js!./src/index.css) 9:36-70
i don't want to define my Background-Images in the tailwind.conf.js
Well you have to. What you're trying to do isn't supported.
The way Tailwind scans your source code for classes is intentionally
very simple — we don’t actually parse or execute any of your code in
the language it’s written in, we just use regular expressions to
extract every string that could possibly be a class name.
so tailwind has no idea what your React code actually means. So it's simply not going to work.
Tailwind does not support dynamic class names:
Don't construct class names dynamically
<div class="text-{{ error ? 'red' : 'green' }}-600"></div>
you should customise your theme to include the image url:
You can add your own background images by editing the
theme.backgroundImage section of your tailwind.config.js file:
tailwind.config.js
module.exports = {
theme: {
extend: {
backgroundImage: {
'hero-pattern': "url('/img/hero-pattern.svg')",
'footer-texture': "url('/img/footer-texture.png')",
}
}
}
}
The solution is to use the style attribute. Thanks for helping :)
<div
className="col-span-full bg- bg-cover grid grid-cols-12 gap-6"
style={{
backgroundImage: `url(${img})`,
}}
>

React set dynamic style in a component

This has been asked several times but in my use case it's not working. I'm sure I'm missing something.
In a functional component I do:
const headerImg = {
backgroundImage: `http://localhost:1337${data.service.main_image.url}`
};
Then in a div I do the following:
<div className="bread-cumbs-area" style={headerImg}>
I'm attempting to use headerImg.backgroundImage as the background image but it's not displaying in my div. Any idea what I'm doing wrong?
Since you're setting the background image in CSS, you need to use the url() CSS function:
const headerImg = {
backgroundImage: `url('http://localhost:1337${data.service.main_image.url}')`
};

Use different profile image sizes in Microsoft Graph Toolkit

In my MGT React SharePoint WebPart, I would like to have some of the profile images displayed with large size (48px), while other images displayed with medium size (36px).
I know the property avatarSize can be used, but this only supports Small, Large or Auto. And in the mgt-person css class, I can specify --avatar-size: 36px. But since this css class affects all person components on the page, all profile images are now sized 36px. And there is no support for specifying a css class on the person component itself.
Do you know if this can be achieved another way?
UPDATE:
I managed to solve this myself with the help from this article:
https://developer.microsoft.com/en-us/graph/blogs/a-lap-around-microsoft-graph-toolkit-day-4-customizing-components/
Using the following definitions in my scss file, it can adjust the avatar size based on for example a WebPart property:
.personsmall mgt-person {
--avatar-size: 24px;
}
.personmedium mgt-person {
--avatar-size: 36px;
}
.personlarge mgt-person {
--avatar-size: 48px;
}
And in my tsx file, it looks like this:
public render(): React.ReactElement<IRolesProps> {
let cf: CommonFunctions = new CommonFunctions();
return (
<div className={this._getAvatarSizeClass(this.props.roleSize)}>
{this.props.roles && this.props.roles.map((val) => {
return (
<Stack className={styles.roleSpacing}>
<Text className={styles.roleHeader} variant="xLarge">{val.role}</Text>
<Person userId={val.person} view=PersonViewType.twolines fetchImage={true} showPresence={true}
personCardInteraction={PersonCardInteraction.hover} line2Property="mail"></Person>
</Stack>);
})}
</div>
);
}
private _getAvatarSizeClass(avatarSize: AvatarSize): any {
if (avatarSize) {
switch (avatarSize) {
case AvatarSize.Small:
return styles.personsmall;
case AvatarSize.Medium:
return styles.personmedium;
case AvatarSize.Large:
return styles.personlarge;
default:
break;
}
}
}
Hope this helps someone else struggling with this.
There is a styling guide: MGT Styling guide
You can simply create a CSS rule and call the desired component. Example from the styling guide
mgt-person {
--avatar-size: 34px;
}
Thus you should be able to combine this with a CSS class such as:
mgt-person.my-avatar-size {
--avatar-size:42px;
}
Since all React components expose a className attribute this should work:
<Person className='my-avatar-size'></Person>
UPDATE
Since, for some reason, there is no className attribute available, why don't you use a data- attribute instead:
mgt-person[data-cssclass='my-avatar-size']{
--avatar-size:42px;
}
<Person data-cssclass='my-avatar-size'></Person>
Hacky, but should work. Also, you might want to look at the actual generated HTML and use this.

Is it possible to refer to css styles as objects in JS code?

I want to be able to do this:
import styles from 'switchstyle.css';
const Choice = function (props) {
const cssClasses = [];
if (props.active) {
// i think .active would be defined in the css file
cssClasses.push(style.active);
}
return (
<div
onClick={props.onClick}
className={cssClasses}
>
{props.label}
</div>
);
};
I saw something like that in a React book, but I cant get it to work -- I think I am missing some webpack plugin (I am guessing). THank you
This should work fine assuming you're using Webpack, except className can't take an array. A simple solution is to make it a string:
className={cssClasses.join(' ')}

get index value from react loop and pass it to css

I created react component that is taking an array and stacking all the progress bars into one.
const ProgressBar = (props, {...customProps}) => {
const GroupProgressBar = [];
props.groups.map((group, i) => {
const widthValue = (group.value / group.max) * 100;
GroupProgressBar.push
(<div style={{width: `${widthValue}%`}}
key = {i}
className={`well-background--${group.concept}
animation
terra-ProgressGroup--progress
terra-ProgressBar--${props.heightSize}`}>
</div>);
})
return <div className='terra-ProgressGroup'> {GroupProgressBar} </div>
}
CSS (classes below i want to convert to single class):
....
.well-background--concept1 {
animation-delay: 1s;
z-index: -1;
}
.well-background--concept2 {
animation-delay: 2s;
z-index: -2;
}
.well-background--concept3 {
animation-delay: 3s;
z-index: -3;
}
I tried to convert these classes into one but have no luck
:root {
--concept-code: key;
--concept-code2: key;
}
.animation {
animation-delay: var(--concept-code)s;
z-index: var(--concept-code2);
}
Basically i dont want keep adding those similar classes so i am trying to create a single class and pass those numbers from react component. probably using key = {i}
How can i achieve that?
Why even bother with CSS for this case? The point of CSS is that the styles cascade and have hierarchy. If the style applies only to a specific React component, then it's best to render the appropriate styles directly.
const ProgressBar = (props, {...customProps}) => {
const GroupProgressBar = [];
props.groups.map((group, i) => {
const widthValue = (group.value / group.max) * 100;
GroupProgressBar.push
(<div
style={{
width: `${widthValue}%`,
animationDelay: /* based on the concept number */,
zIndex: /* based on the concept number */
}}
key = {i}
className={`well-background--${group.concept}
animation
terra-ProgressGroup--progress
terra-ProgressBar--${props.heightSize}`}>
</div>);
})
return <div className='terra-ProgressGroup'> {GroupProgressBar} </div>
}
Note that I'm not sure how you can generate the appropriate number for your style because I don't know your data structure. But that would be trivial enough. The important part is just rendering the style in the component instead of CSS.
There's not really a great way to dynamically inject CSS class style definitions into the page with React. And even so, that would be vastly over-engineering a solution for this problem. Better to just create lots of .well-background class definitions in the CSS manually, as many as you think you'll need (10? 20? How many will there really be?).

Resources