Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding styled components component selector and ampersand

In styled-components docs, they have this example:

https://www.styled-components.com/docs/advanced#referring-to-other-components

enter image description here

It shows an Icon that changes color when you hover its parent, which is a link, in this case.

const Link = styled.a`
  display: flex;
  align-items: center;
  padding: 5px 10px;
  background: papayawhip;
  color: palevioletred;
`;

const Icon = styled.svg`
  flex: none;
  transition: fill 0.25s;
  width: 48px;
  height: 48px;

  ${Link}:hover & {         // <---- This is what I'm not understanding
    fill: rebeccapurple;
  }
`;

From the Docs, we know that:

Doc Note #1: styled-components solves this use case cleanly via the "component selector" pattern. Whenever a component is created or wrapped by the styled() factory function, it is also assigned a stable CSS class for use in targeting.

And also that:

Doc Note #2: Ampersands (&) get replaced by our generated, unique classname for that styled component, making it easy to have complex logic.


Let's analyze ${Link}:hover &

I know it gets translated into the browser as:

enter image description here

and:

enter image description here

I understand that sc-kAzzGY is the "stable CSS class" (Doc Note #1) that is created whenever an element is wrapped by the styled function.

I also know that the Ampersand (&) gets replaced by their generated unique classname (Doc Note #2) for that styled components. Hence, kDmLky is that class.

QUESTION

But what does the resulting selector (picture below) is actually selecting? Can anybody explain that to me?

enter image description here

like image 474
cbdeveloper Avatar asked May 01 '19 17:05

cbdeveloper


1 Answers

${Link} is pointing to const Link i.e.: "Hovering my parent changes my style" which gets a class of sc-kAzzGY.

& is kinda like saying "And add this to the current class(es)/id(s)/etc." So,

.my-class {
 some-css: awesomeness;
 &:hover {
   more-css: extra-cool;
 }
}

is equivalent to:

.my-class {
 some-css: awesomeness;
}
.my-class:hover {
   more-css: extra-cool;
}

Therefore, & points to the containing element const Icon i.e. the speech bubble and gets a class of kDmLky.

When Link is hovered, cause Icon to have fill: rebeccapurple

EDIT:

Just to clarify things a bit more:

When you have a declaration block inside of another declaration block like the example below, that inner declaration block becomes an independent one.

const Icon = styled.svg`
  flex: none;
  transition: fill 0.25s;
  width: 48px;
  height: 48px;

  ${Link}:hover & {       // This declaraition block becomes an independent one
    fill: rebeccapurple;
  }
`;

And the result, in this case, is a declaration block with a selection that says:

When you have a class & which is descendent of the class ${Link} which is in the hover state, apply these rules:

fill: rebeccapurple;

NOTE: ${Link} refers to the Link class and & refers to the Icon class (svg).

like image 177
iosepa Avatar answered Sep 18 '22 13:09

iosepa