0

I have an SVG checkbox with a circle element surrounding a polyline element (the checkmark). Because the icon boundaries extend beyond the circle, using &:hover on the icon itself means you see the styles change when hovering outside the borders of the circle. So I want to only change styles on :hover over the circle itself. But I obviously need to change both the circle and the polyline on hover. I'm using styled-components.

I've tried everything I can think of to get the polyline to change on circle hover.

I began by trying something like:

& circle:hover circle, & circle:hover polyline { }

and several variations on this. Eventually I made the circle and polyline elements into styled components in order to more easily interpolate them. Based on this post I attempted this solution:

const Circle = styled.circle``;
const Polyline = styled.polyline``;

const Icon = styled.svg`
  width: 52px;
  height: 52px;

  & ${Circle}, ${Polyline} {
    fill: #fff;
    stroke: ${props => props.logged ? colors.secondary200 : colors.secondary400};

  & ${Circle}:hover {
    stroke: ${colors.secondary400};
    fill: ${colors.secondary400};
  }

  & ${Circle}:hover ${Polyline} {
    stroke: #fff;
    fill: ${colors.secondary400};
  }

But the polyline still doesn't change when hovering over the circle. I also tried nesting:

  & ${Circle}:hover {
    stroke: ${colors.secondary400};
    fill: ${colors.secondary400};

    & ${Polyline} {
      stroke: #fff;
      fill: ${colors.secondary400};
    }
  }

Nothing seems to be working. How should I be selecting this polyline?

EDIT: I realized based on styled-components documentation that it might be better to handle this styling in the Polyline styled-component, so I put the following together:

const Polyline = styled.polyline`
  pointer-events: none;
  fill: #fff;
  stroke: ${props => props.logged ? colors.secondary200 : colors.secondary400};

  ${Circle}:hover & {
    stroke: #fff;
    fill: ${colors.secondary400};
  }
`;

This still doesn't work, but ${Icon}:hover & { } does work for some reason. I still can't use it because the Icon's boundaries are outside the circle, but I am utterly at a loss for why the Polyline responds to hovering over the Icon but not the Circle. The Circle is definitely receiving a hover event because it applies its own :hover styles. Apparently Polyline is ignoring it though.

See JSFiddle here

ipenguin67
  • 1,483
  • 5
  • 22
  • 39

1 Answers1

1

Here is the solution: https://jsfiddle.net/x9j7ku8o/3/

The important bit being this:

const Circle = styled.circle`
  &:hover+${Polyline} {
    stroke: #fff;
    fill: #21ccbf;
  }
`;

The problem was that you were using the descendant combinator (by using a space between Circle and Polyline in the css selector), but Polyline isn't a descendant of Circle.

Polyline and Circle are siblings, so you must use one of the sibling combinators: either the adjacent sibling combinator or the general sibling combinator. I used the adjacent one, since Polyline and Circle are adjacent.

Important to note that the order matters: I use the combinator &:hover+${Polyline} in Circle because in your example's html, Circle comes before Polyline.

Raicuparta
  • 2,037
  • 15
  • 22
  • This worked great, thanks so much! Of course it ended up being a simple CSS issue and not some crazy React trickery. – ipenguin67 Aug 15 '19 at 22:17