question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dynamic style composition with cx and the css prop breaking & + & selectors

See original GitHub issue

Current 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

  1. Write a set of CSS that is “static” (no string interpolation), that includes the & + & selector.
  2. 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 the css prop).
  3. 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.6
  • emotion version: 10.0.9

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

5reactions
Andaristcommented, Jun 26, 2019

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:

const Container = styled.div`
  ${({ adjacent }) => adjacent && { marginTop: 20 }}
`;

const Component = () => {
  return (
    <>
      [1, 2, 3].map((_, i) => <Container adjacent={i > 0} />)
    </>
  );
};

1reaction
Andaristcommented, Oct 27, 2019

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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

difference between css and Styled in emotion js - Stack Overflow
I think the main difference would be that css just generates a selector with a specific set of CSS properties, whereas styled requires...
Read more >
@emotion/serialize | Yarn - Package Manager
Introduction · Install · CSS Prop · Styled Components · Composition · Nested Selectors · Media Queries. Quick Start. Get up and running...
Read more >
Styling themes
Style composition is best at the component level and made prototyping in the browser unbelievably quick; Design system constraints are powerful (and developers ......
Read more >
Compile time CSS-in-JS vs CSS-in-JS vs CSS Modules vs SASS
But compilation step bring to us some limitations, like css'' fn so crazy dynamic, it is just like css scoped class. And your...
Read more >
developing-open-storefront-framework-applications-oracle-cx ...
use and disclosure and are protected by intellectual property laws. ... to create Oracle CX Commerce storefront applications. ... [cli] info: styles.css.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found