How to use a dynamic background image URL with Tailwind CSS and React - reactjs

In React, I'm unable to use a URL string in my Tailwind background image class:
1: Not working, getting error "can't resolve ${link}"
const link = "https://cdn.test.net/test.jpg";
<div className={`px-4 py-1 h-[22rem] lg:h-[28vw] bg-cover bg-center bg-[url('${link}')]`}></div
2: Working, but I need to use a variable inside my bg- class.
const link = "bg-[url('https://cdn.test.net/test.jpg')]";
<div className={`px-4 py-1 h-[22rem] lg:h-[28vw] bg-cover bg-center ${link}`}></div>
I still need to be able to use ${link} inside bg-[url('${link}')].

Here is how it looks for me
The given example should be working fine.
Working fine for me.

The CSS file generated by Tailwind will only include classes that it recognizes when it scans your code, which means that dynamically generated classes (e.g. bg-[url('${link}')]) will not be included.
If you only have a few different background images, you could add them to your tailwind.config.js and switch between them:
module.exports = {
theme: {
extend: {
backgroundImage: {
'first': "url('/img/first.jpg')",
'second': "url('/img/second.jpg')",
}
}
}
}
<div className={`bg-cover bg-center ${useFirst ? 'bg-first' : 'bg-second'}`}></div>
This would work, as long as you use the full utility class name, e.g. bg-first, in the code for Tailwind to find and include in the generated CSS.
If you need to reference completely arbitrary URL values, you can always use a style attribute instead of Tailwind classes. For example:
<div className="bg-cover bg-center" style={{backgroundImage: `url('${link}')`}}></div>

Related

Applying the class name through json not working, same works if hardcoded

It's my json:
export const initialInitialPropsSchema: InitialProps[] = [
{ className: 'text-secondary text-5xl font-semibold', label: 'B' },
{ className: 'text-white text-5xl font-semibold', label: 'M' },
{ className: 'text-tertiary text-5xl font-semibold', label: 'A' },
];
my header: where I apply my class names on loop:
export const Header: FC<{ initials: InitialProps[] }> = ({ initials }) => {
return (
<div className="p-5 bg-primary flex justify-between">
{initials.length &&
initials.map((initial) => (
<h1 key={initial.label} className={initial.className}>
{initial.label}
</h1>
))}
</div>
);
};
But in the browser I see all class names are applied. But no property update with element. If I hard code the classNames, instead of assign from json it works fine. I am using Nx workspace with vite for react app. the header placed under the header library.
in browser I see this:
UPDATE
In my header part, I simply added all classes what it's used in json like this: ( apart from loop as static )
<h1 className="text-secondary text-tertiary text-white text-5xl font-semibold"></h1>
then all look classes as well works. what would be the issue? how to solve this?
This is most likely due to the Tailwind compiler not including those classes in the generated CSS. As stated in the documentation, here and here
Tailwind doesn’t include any sort of client-side runtime, so class names need to be statically extractable at build-time, and can’t depend on any sort of arbitrary dynamic values that change on the client.
This is because Tailwind tries to optimize your bundle size by removing unused classes and it needs to be able to determine which of those to keep at build time which it seems is not possible in this case due to classes being assigned to variables.

How do you use Tailwind animate classes with React Hooks?

For example - add animate-ping upon new message from a web-socket.
Tailwind just-in-time is likely to be the reason why you can't do that.
Basically, if animate-ping is not scraped in your files, adding it through Javascript or any other way later will simply not work, as the CSS file generated will not include animate-ping.
You should likely make your very own class in your CSS, even if it means using #apply directive of Tailwind. Adding Tailwind class later on in the DOM that were never parsed at build time will simply.. not works.
To conditionally show a class would be something like this:
function Notification() {
const [isNotification, setIsNotification] = useState(false);
return (
<div className={` ${isNotification ? "animate-ping" : null} h-2 w-2 m-5 bg-sky-400 rounded-full`}></div>
);
}

How to pass custom class name on react and use scss?

I am trying to create a react component that has the class name as props being passed,
I have managed sending the props part successfully, however when I try to set the scss for the updated class name, I could not find a way to fix that, all of your input is appreciated.
Code of the component
Code of injecting the custom style class
Styles of the Variation
Output
Output of the Variation Class
Output of the Stylesheet
not sure what I am missing to connect all of them.
Thanks in advance.
As mentioned by Phil, your SCSS should be using &.secondary as the selector.
As for the difference in your scss class IDs and them not matching when you pass ${variant} to the className, your issue is that you are passing a raw string as the variant to the className and are using CSS modules for your SCSS (this is what handles namespacing them/adding the unique characters). To fix this, you need to use the imported style rather than a raw string for the className.
The way I usually address this is with an enum as the prop for different variants, or if there are only two a boolean, and then apply the imported style accordingly. A quick example of this, using your code would be:
const SectionTitle: FC<SectionTitleProps> = ({ title, isSecondary = false }) => (
<h3
className={`${styles.SectionTitle}${isSecondary ? styles.secondary : ''}`}
...
>
...
</h3>
);
I also find the classnames library helpful for this. It allows you to achieve the above with something I find a bit more readable, such as:
<h3
className={classNames(styles.SectionTitle, { [styles.secondary]: isSecondary } )}
...
>
...
</h3>
EDIT: Also including an example using classnames with an enum for different variants:
enum TitleVarient {
Default,
Secondary,
Accent,
}
const SectionTitle: FC<SectionTitleProps> = ({
title,
variant = TitleVarient.Default,
}) => (
<h3
className={classNames(styles.SectionTitle, {
[styles.secondary]: variant === TitleVarient.Secondary,
[styles.accent]: variant === TitleVarient.Accent,
})}
...
>
...
</h3>
);

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})`,
}}
>

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.

Resources