Dynamic style composition with cx and the css prop breaking & + & selectors
See original GitHub issueCurrent behavior:
With either the emotion
or @emotion/core
packages, using the & + &
selector as part of a call to css()
that is composed with dynamically-set styles causes the selector to not work as intended.
To reproduce:
Reproduced with @emotion/core
using the CSS prop: https://codesandbox.io/s/kind-jepsen-fve70
Reproduced with the emotion
package using cx
: https://codesandbox.io/s/proud-water-6uzkl
- Write a set of CSS that is “static” (no string interpolation), that includes the
& + &
selector. - Write a component that has styles set based on a passed-in prop (using string interpolation), and compose those with the styles written as a part of step 1 (via
cx
or thecss
prop). - Render multiple of these components as siblings.
If you follow the above steps, sibling elements will not be selected as you would expect with the & + & selector. The <style>
tags added to the page appear to include a & + &
selector with different classNames for each instance of the selector due to creating a single className including both the dynamic and statically-defined styles for each variation on the styles, rather than outputting two classNames and sharing one of them between each component instance.
Expected behavior:
Multiple classNames should be output from cx
or the css
prop on each element, where one className is the same amongst all siblings so that the & + &
selector can be utilized like it can be in any number of CSS preprocessors. In the code sandbox links provided, the second and third squares should be red.
I would expect the following to happen:
const staticStyles = css`
width: 50px;
background-color: red;
& + & {
background-color: blue;
}
`
const TestComponent = ({ color = 'blue' }) => <div className={cx(staticStyles, css`color: ${color};`)} />
...
<TestComponent color='purple' />
<TestComponent color='orange' />
Should render something like:
<style>
.css-1wpld8c-TestComponent {
width: 50px;
background-color: red;
}
.css-1wpld8c-TestComponent + .css-1wpld8c-TestComponent {
background-color: blue;
}
</style>
<style>
.css-klhj53jhkj-TestComponent { color: purple; }
</style>
<style>
.css-djciui7kjb-TestComponent { color: orange; }
</style>
<div class="css-1wpld8c-TestComponent css-klhj53jhkj-TestComponent"></div>
<div class="css-1wpld8c-TestComponent css-djciui7kjb-TestComponent"></div>
Environment information:
react
version: 16.8.6emotion
version: 10.0.9
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:9 (5 by maintainers)
Top GitHub Comments
Emotion indeed restricts some css patterns - ideally we would like to cover all use cases, but that’s just hard and considering pros and cons of the used approach we believe that those are tradeoffs worth the received benefits.
Ofc you can always attempt to prepare a PR fixing this while preserving existing tests intact.
The workaround could be:
Closing this, because it really doesn’t seem to be solvable by emotion. It’s just that
&
refers to something else that you have expected here as it refers to a final computed class name, rather than some kind of stable one. Because we flatten composed styles into a single class name to make things predictable (independent of insertion order) this just cannot refer to a stable class.