compiled icon indicating copy to clipboard operation
compiled copied to clipboard

Decide on long-term solution on ampersand in CSS selectors (e.g. `:hover` and `&:hover`) in `styled` and `css` APIs

Open dddlr opened this issue 1 year ago • 0 comments

ty @kylorhall-atlassian for bringing this up internally and for providing the examples.

With SCSS and the upcoming CSS Nesting module, there is a distinction made between:

  • :hover (targeting a child element, like .class :hover or .class *:hover) and
  • &:hover (targeting the current element, like .class:hover)

Examples include SCSS and CSS Nesting module

The Compiled css and styled APIs treat both :hover and &:hover as targeting the same element (self), instead of a child element. In other words, a developer may write this without realising that both color and backgroundColor are actually targeting the same <div> element:

<div css={css({
    ':hover': { color: 'blue' }
    '&:hover': { backgroundColor: 'pink' }
})}>Hello world</div>

On the other hand, cssMap and xcss only allow &:hover, with :hover not being valid according to the typescript types: https://github.com/atlassian-labs/compiled/blob/9857009f59f2089ca8c026745f3070b0e7b02e4c/packages/react/src/types.ts#L45

Perhaps we should change css and styled to forbid :hover, and only allow &:hover. Of course, this doesn't just affect :hover, but also every other CSS selector that exists.

Potential solutions:

  • Create ESLint rule to convert all ampersand-less selectors to ampersand-ful ones. Then require the ampersand-ful version &:hover through typing and runtime checks, in time for v1 release.
    • Recommended for consistency with CSS Nesting, Emotion(?), xcss and cssMap APIs, Sass, etc.
  • The above solution, but instead, converting all ampersand-ful selectors to ampersand-less ones.
    • Not sure if there are any pros to this

Unresolved problems:

  • What if a developer wants to use :hover for a child element?
    • Potential solution: discourage them from doing this in the first place (only allow styles to apply to the current element), or use *:hover as a workaround instead?

dddlr avatar Dec 19 '23 22:12 dddlr