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...