DEV Community

glocore
glocore

Posted on

Configure Emotion with your Vite React Project

@vitejs/plugin-react-refresh was migrated into @vitejs/plugin-react, and many Emotion + Vite tutorials and boilerplates out there became outdated as a result.
The Vite monorepo has an example react-emotion setup, which seems to works quite well. Here's the gist:

1. Install Emotion Dependencies

Make sure you have the following installed:

yarn add @emotion/react
yarn add -D @emotion/babel-plugin
Enter fullscreen mode Exit fullscreen mode

2. Update vite.config.js

The @vitejs/plugin-react plugin accepts a custom babel config via the babel option. Here, we add the @emotion/babel-plugin plugin we just installed.
Also, to be able to use the css prop in our JSX, we need to instruct @vitejs/plugin-react to use Emotion's jsx function instead of the default jsx-runtime when compiling JSX. We do this by setting the jsxImportSource option to @emotion/react.

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react({
      jsxImportSource: "@emotion/react",
      babel: {
        plugins: ["@emotion/babel-plugin"],
      },
    }),
  ],
});
Enter fullscreen mode Exit fullscreen mode

Optional: TypeScript support

When using Emotion with TypeScript, your editor may complain that css is not a valid prop. This is because by default, css is not a recognised prop in React and your TypeScript compiler doesn't know about Emotion. Fix this by instructing TypeScript to use types from Emotion instead:

{
  "compilerOptions": {
    "jsxImportSource": "@emotion/react"
  }
}
Enter fullscreen mode Exit fullscreen mode

Hope this helps!

Top comments (6)

Collapse
 
ndh103 profile image
NDH103

thank you, this saved me a lot of effort

Collapse
 
vfonic profile image
Viktor • Edited

I'm trying to use component selectors in my emotion styles. Did you have any luck doing so?

For example, I have this OnOffSwitch component which has some child elements:

const OnOffWrapper = styled.div`
  display: inline-block;

  ${props =>
    props.isChecked
      ? `
    ${OnOffTrack} {
      background-color: ${props.color};
      border: 1px solid ${props.color};
    }
    ${OnOffHandle} {
      transform: none;
      background-color: ${props.color};
    }
  `
      : `
    ${OnOffTrack} {
      background-color: transparent;
      border: 1px solid ${colors.silver};
    }
    ${OnOffHandle} {
      transform: translateX(-100%);
      background-color: ${colors.silver};
    }
  `}
`;
Enter fullscreen mode Exit fullscreen mode

These styles (anything below display: inline-block;) are being ignored now.

I've found this, but there's no mention of how to achieve this with Vite: github.com/emotion-js/emotion/issu...
Also this, which throws an error immediately ("Uncaught SyntaxError: missing ) after argument list"):
stackoverflow.com/questions/614352...

Here's my full vite.config.js (I use Vite in a Rails app):

import react from '@vitejs/plugin-react';
// import ViteReact from '@vitejs/plugin-react-refresh';
import { defineConfig } from 'vite';
import Environment from 'vite-plugin-environment';
// import eslintPlugin from 'vite-plugin-eslint';
import FullReload from 'vite-plugin-full-reload';
import RubyPlugin from 'vite-plugin-ruby';

export default defineConfig({
  esbuild: {
    jsxFactory: 'jsx',
    jsxInject: `import { jsx } from '@emotion/react'`,
  },
  plugins: [
    // eslintPlugin(),
    react({
      jsxImportSource: '@emotion/react',
      babel: {
        plugins: ['@emotion/babel-plugin'],
      },
    }),
    Environment({
      CLOUDINARY_API_KEY: null,
      CLOUDINARY_CLOUD_NAME: null,
      GOOGLE_MAP_API_KEY: null,
      INTERCOM_APP_ID: null,
      MAPBOX_API_KEY: null,
      STRIPE_PUBLISHABLE_KEY: null,
    }),
    RubyPlugin(),
    FullReload(['config/routes.rb', 'app/views/**/*'], { delay: 200 }),
    // ViteReact(),
  ],
  resolve: {
    alias: [
      {
        find: /^react-mapbox-gl/,
        replacement: 'react-mapbox-gl/lib',
      },
    ],
  },
});
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rossthedevigner profile image
rossthedevigner

@vfonic I just spent the last few hours trying to debug this exact scenario! Did you ever find a solution?

Collapse
 
elvezpablo profile image
Paul

I ran across this issue and found that it was caused by Vite doing some extra code injection (github.com/vitejs/vite/issues/9829). It happened when I was trying to bundle emotion as a module. I ended up removing emotion from the module and using it as a dependency at the root of my project.

Collapse
 
tiendatleo profile image
Nguyen Tien Dat

Thank you very much!

Collapse
 
tranquilmarmot profile image
Nate Moore

Thank you so much for this 🙏

Surprised this isn't in the official Emotion docs yet...