React styled-components – How to render styles based on prop condition or pseudo class?

Issue

I am trying to conditionally render a hover state / view within styled-components, leveraging the props coming in from react…

Currently, my code looks something like this:

${isHovered}, &:hover {
    background: red;
}

Unfortunately, this does no work to be able to have a true/false as I am missing something I presume to be able to do the either / or pseudo..

I want to be able to explicitly show the hover state while retaining the default pseudo hover. How can I achieve this?

Solution

The way you have your selectors right now is invalid:

Problem

${isHovered}, &:hover {
    background: red;
}

As of now, this will always translate to:

undefined, &:hover {
    background: red;
}

For simplicity, in order to interpolate properly, it must be a function accepting props that returns a string:

color: ${props => props.isHovered && "pink" };

On a related note, even if you wrapped your styled component in a higher order component where isHovered is defined as an argument, it unfortunately still won’t work in production for styled-components v5 — this worked in v4, but v5.x doesn’t handle css interpolations properly within a styled component when compiled for production (see issue tracker here).

Solutions

A better and recommended approach would be to interpolate within a CSS property:

  background: ${({ isHovered }) => isHovered && "red"};

  :hover {
    background: red;
  }

Alternatively, if you have multiple CSS rules, then you can interpolate outside of a CSS property:


  ${({ isHovered }) => isHovered && "background: red;color: white;"};

  :hover {
    background: red;
  }

Now you just would pass your component an isHovered prop.

<StyledComponent isHovered={isHovered} />

Although, technically you can do this (notice that falsey values equate to true, which may be a bug or an unhandled edge case) …

${({ isHovered }) => !isHovered && ".hovered"}, &:hover {
    background: red;
}

…it is NOT recommended because of how it’s being interpreted:

".hovered", &:hover {
    background: red;
}

Arguably, this isn’t what you’d want because .hovered isn’t being used at all within the DOM, which may be confusing to other developers. Instead, it reuses the compiled hashed class name to add the CSS property within another rule (focus on the Styles tab to see the difference):
screenshot

While the recommended approach sets the CSS property to the hashed class within the same rule block:
screenshot


Working demo (this demo includes both example codes above, where Title uses the recommended approach and SubTitle doesn’t):

Edit Styled Components - Parent Hover

Answered By – Matt Carlotta

Answer Checked By – Marilyn (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.