Agustín Dorado
Agustín Dorado

Reputation: 309

How to dynamically add css style to pseudo classes in React

I'm trying to build a React component that shows multiple images stored in a database, where below each thumbnail image there is a button linking to its dedicated page. Now, I would like each button to show the dominant color of the image as background on hover. I already have the colors stored in database (artwork.palette.DOMINANT), but struggles to pass the hex code to the React component.

The problem is, inline style cannot set properties of pseudo selectors like a:hover, and because the color is dynamically fetched with the artwork object, I can not set it in a global and static css. Is there a way to set component-scoped style in React? Presumably like <style scoped>...</style>.

Here is my code, I only kept the gist of it for simplicity's sake.

const ImageBox = ({ artwork }) => {
    return (
        <Fragment>
            <div className="image">
                <img src={artwork.resources.THUMBNAIL} alt={artwork.title} />
            </div>
            <div className="caption">
                <span>By {artwork.artist}.</span>
            </div>
            <div className="button">
                <a href="!#" style={{ color: artwork.palette.DOMINANT }}>
                    Details
                </a>
            </div>
        </Fragment>
    );
};

Upvotes: 6

Views: 2687

Answers (3)

moshfiqrony
moshfiqrony

Reputation: 4723

I was looking for how to set styles dynamically. My main intention was to write a style for hover. Using state to track whether it is hovered or not is good but that will cost render for each update. So I thought How I can solve it with out any state change. I end up doing this and it works perfectly.

<a
  target='_blank'
  href="#"
  onMouseOver={(e) => e.target.style.color = 'red'}
  onMouseOut={(e) => e.target.style.color = ''}
>
    This is my link
</a>

Upvotes: 2

Agust&#237;n Dorado
Agust&#237;n Dorado

Reputation: 309

Thanks to @PramodMali, I found the CSS-in-JS approach as a elegant way to solve this problem. For anyone who stumbles upon the same struggle in the future, here's how I solved it with react-css:

import { createUseStyles } from "react-jss";

const useStyles = (dominantColor = "#fff") =>
    createUseStyles({
        toDetailPage: {
            color: dominantColor,
            "&:hover": {
                color: "#000",
                background: dominantColor,
            }
        }
    });

After defining the style generator, use it to dynamically set classes in component:

const ImageBox = ({ artwork }) => {
    const classes = useStyles(artwork.palette.dominant)();
    return (
        <Fragment>
            <div className="image">
                <img src={artwork.resources.THUMBNAIL} alt={artwork.title} />
            </div>
            <div className="caption">
                <span>By {artwork.artist}.</span>
            </div>
            <div className="button">
                <a href="!#" className={classes.toDetailPage}>
                    Details
                </a>
            </div>
        </Fragment>
    );
};

This will then generate dynamic classes on render, for instance detailsButton-0-2-7, which applies the properties passed to the generator function when defining classes.

Upvotes: 3

Pramod Mali
Pramod Mali

Reputation: 1798

You could use JS to modify the global properties of CSS.

  1. Declare properties in index.css or App.css and add your basic styles that will utilize these variables.
:root {
  --color-surface: white;
}

button {
  background: var(--color-surface);
}
  1. Modify these properties using JS(onMouseEnter and onMouseLeave). i.e.
//onMouseEnter
document.documentElement.style.setProperty("--color-surface", "black");

//onMouseLeave
document.documentElement.style.setProperty("--color-surface", "white")

There a few references you can follow:

Blog and CodSandBox

Note: Not sure if it's a good practice(I haven't seen in projects I've worked on), I would recommend using CSS-in-JS or libraries such as styled component.

Upvotes: 4

Related Questions