emotion icon indicating copy to clipboard operation
emotion copied to clipboard

Difficulty understanding the usage of `cx` between packages

Open neefrehman opened this issue 5 years ago β€’ 10 comments

Description:

I've just started migrating a project to emotion, and am struggling to understand the usage patterns of the cx function from @emotion/css, specifically around two areas.

  1. Short circuiting values for conditional classNames: cx(state && className)

    There's no mention of this in the documentation, only the object-based { [className]: state } method, but I see it is possible after testing it out. Is this considered a bad or deprecated pattern? I'm coming from another library which supports it, and prefer the approach.

  2. Including SerializedStyles from @emotion/react's css

    This doesn't work in cx, and forces me to use css from @emotion/css instead, but leaves me wondering if I'm choosing the right method for adding extra classNames? It feels like the react package should be the best css function to use, since I'm styling a React component. I think I would prefer there to be a version of cx exported from /react, which supports combining SerializedStyles as well so that I can remove the /css package, if that's possible.

Overall I feel like I'm juggling between three packages (/styled, /css, /react) a little too much, which often leaves me confused. Some extra documentation around these choices would be helpful.

Edit: in case it's useful, I prefer the styled method over the css prop method.

Documentation links: https://emotion.sh/docs/@emotion/css#cx

neefrehman avatar Dec 01 '20 19:12 neefrehman

Also weirdly looking at the node_modules/@emotion/react/types/index.d.ts it states an interface cx but it doesn't work to import cx from import {cx} from '@emotion/react';.

export interface ClassNamesContent {
  css(template: TemplateStringsArray, ...args: Array<CSSInterpolation>): string
  css(...args: Array<CSSInterpolation>): string
  cx(...args: Array<ClassNamesArg>): string
  theme: Theme
}

I would also prefer to only import one single module and then work with it the same way https://github.com/JedWatson/classnames works. So I'd rather import that for now than using three different packages of emotion.

Primajin avatar Feb 07 '21 12:02 Primajin

Those types don't declare a standalone cx helper but rather a function available to render prop of the ClassNames component.

Andarist avatar Feb 08 '21 07:02 Andarist

Same here, confusing on how to import cx method from @emotion/react instead of installing @emotion/css

max8hine avatar Jul 04 '21 22:07 max8hine

same here

masterambi avatar Jul 05 '21 07:07 masterambi

Same. Anyone can help? It’s a pain people cannot import cx from emotion/react

cjnoname avatar Nov 07 '21 19:11 cjnoname

I am using a hook within I need to use cx because there is a property called cellClass and i need to merge two classes. If i try use emotion/react, i can only use cx with <ClassNames> (?? no sense, i don't render nothing there ???) so i must use cx from emotion/css...

It seems like i kind an error....

vivaslj1 avatar Nov 22 '21 16:11 vivaslj1

I run into the the same issue. But Isn't this this supposed to be the answer? https://emotion.sh/docs/@emotion/react#cx

pietrop avatar Jul 25 '22 03:07 pietrop

If you're using @emotion/react or @emotion/styled, there is no need to install the @emotion/css package at all. The cx function from @emotion/css should only be used when generating class names with @emotion/css.

You can use the css function from @emotion/react to combine multiple object styles, CSS strings, SerializedStyles, .etc. The css function and css prop also support conditional styles like this:

const baseCss = css({ color: 'blue' })
const activeCss = css({ backgroundColor: 'gray' })

function MyComponent({ active }) {
    return <div css={[baseCss, active && activeCss]} />
}

The only context where cx is relevant when using @emotion/react or @emotion/styled is when using <ClassNames>, which is documented here.

I'm going to try to improve the documentation around combining CSS & conditional CSS using the css function since we don't currently have a great example of it.

srmagura avatar Jul 31 '22 15:07 srmagura

Thanks all for this thread.

I add also my confusion and what I have understood about the migration from Emotion Css to Emotion React.

I landed here because I just needed to add a class string to a className from an external stylesheet (in my case for a icon class Name) and I didn't understand how to do it with Emotion React.

Before using Emotion React with Emotion CSS, I could do:

<div
  className= {cx('my-icon-class-name', props.className, css`....`)}
>
</div>

Easy to read (minimal boilerplate), easy to write, great! Thanks.

It took me some time to go over to Emotion React. From what I understand,

  • For the Emotion CSS cx function, you need to use the ClassName component (to integrate an external class name), this is way backward in terms of simplicity and boilerplate.
  • For the Emotion CSS css function, you need to use it within the special css prop (the Emotion React css function creates an object and not a class name as the Emotion CSS css function)

I didn't see any added value of Emotion React, except Server side rendering and a sort of cascading optimization. The css prop adds also an extra burden (typescript does not like it by default as any third-party UI library).

I'm just lost now on which option I need to take.

gerardnico avatar Mar 15 '24 09:03 gerardnico

Quick Update: I migrated to the styled interface as:

  • it's a nice way to attach css properties to a component
  • it does not require any typescript configuration
  • it's a defacto common standard (used by styled, mui, ...)

It would be great to have one package (or documentation) that is configured towards the styling interface.

Example:

  • emotion-css
  • emotion-react-css-prop
  • emotion-react-styled

As a newbie, I was so confused.

And for cx, I have recreated it to concatenate classNames.

cx(...classes: (string | undefined | null)[]) {
        // Filter out null and undefined values
        const validClasses = classes.filter(arg => arg !== null && arg !== undefined);
        // Join the non-null and non-undefined strings with a space
        return validClasses.join(' ');
}

Thanks

gerardnico avatar Mar 15 '24 12:03 gerardnico