Emotion: @emotion/react: Support using theme props with `css` API

Created on 11 Feb 2021  路  8Comments  路  Source: emotion-js/emotion

The problem

Existing css from @emotion/react doesn't support accessing theme props as such:

const mixin = css`
  color: ${props => props.theme.colors.primary}
`'

Proposed solution

Please support it as it is helpful for React developers:

  • Allow use cases in theme definitions, mixins, helpers, etc. where accessing theme props is required
  • Users migrating to Emotion from Styled Components will be blocked by the lack of this feature

No specific solution from me but styled-components is a good example.

Alternative solutions

N/A

Additional context

Similar issue: #801

feature request needs triage

Most helpful comment

You can also just refactor this to:

const mixin = theme => css`
  color: ${theme.colors.primary}
`'

All 8 comments

I see a few other options as temporary workarounds:

  • The useTheme can be used inside a component.
  • Just import the theme object and use it raw in the mixin. The only difference (as far as I see) is the lack of reactivity, which can be solved by hooking the component up to the useTheme hook.

You can also just refactor this to:

const mixin = theme => css`
  color: ${theme.colors.primary}
`'

An example of @Andarist answer implemented in typescript can be found here.

I think the answer has been given - if you have any further questions please open a discussion thread.

@rickstaa Your link does not seems to be working. Can anyone give me an example of a typescript implementation?
When I do

const mixin = theme => css`
  color: ${theme.colors.primary}
`

I get the error Parameter 'theme' implicitly has an 'any' type.

And when I do

const mixin = ({ theme }) => css`
  color: ${theme.colors.primary}
`

I get the error Binding element 'theme' implicitly has an 'any' type.

I've made a codesandbox of the problem:
https://codesandbox.io/s/emotion-11-css-api-typescript-6dv8r?file=/src/Div.styled.ts

@StevenVerbiest, I think I changed the code-sandbox name somewhere after I posted the example. I updated the link to https://codesandbox.io/s/emotion-material-ui-example-ni92b?file=/src/App.tsx. I think for your example you should use the following syntax:

// 3. Use the material-ui theme inside the CSS api
// Re-declare the Emotion theme to the Material-ui theme
declare module "@emotion/react" {
  export interface Theme extends MaterialUITheme {}
}
// Use theme inside the CSS api
const ButtonStyle = (theme: MaterialUITheme) => css`
  background: ${theme.palette.info.main};
`;

You can then use the buttonstyle as follow:

<Button css={ButtonStyle(themeHooked)}>
    CSS API (useTheme) button
</Button>

Let me know if that solves your problem.

@rickstaa Thank you for the update!

Your solution is similar to a workaround we had to do when implementing a custom theme interface (which is fixed in version 11).

It would be nice if the css api would also use the custom Theme interface instead of having to pass it every time we use it.

@StevenVerbiest I'm not sure if I understand the improvement your suggesting. Maybe you can elaborate a bit on it. When you use solution 3 in the sandbox the CSS API is able to use the custom theme without us having to pass it. The type declaration is there just to make typescript happy. Due to how typescript is typed I think there is no way to get rid of this type of definition.

I think the improvement your looking for is similar to what I asked in https://github.com/emotion-js/emotion/discussions/2291. After a discussion with @Andarist, I however agree that the module declaration overload is currently the cleanest solution we can support.

Was this page helpful?
0 / 5 - 0 ratings