6

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>
    );
};
2
  • Are you using .css/.scss/.less files for styles or CSS-in-JS? Commented Aug 17, 2020 at 4:36
  • @PramodMali Thanks for replying. All my classNames come from the global import "./App.css" in App.js (generated by create-react-app), and the rest is just inline style. I am new to react and just experimenting with basic stuff, so I am open to learn .scss/.less or anything of the sort if they can get the job done. Commented Aug 17, 2020 at 4:46

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the solution. I directly went for the CSS-in-JS approach and it worked like a charm. And it's a simple and easy-to -understand solution. Many thx :D
3

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.

Comments

2

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.