Skip to content
+

Using styled-components

Learn how to use styled-components instead of Emotion with Material UI.

By default, Material UI uses Emotion to generate CSS styles. All components rely on the styled() API to inject CSS into the page. This API is supported by multiple popular styling libraries, which makes it possible to switch between them in Material UI.

We provide two different packages to wrap your chosen styling solution for compatibility with Material UI:

  • @mui/styled-engine: a thin wrapper around Emotion's styled() API that includes required utilities like the <GlobalStyles /> component, the css and keyframe helpers, and more. This is the default, and you do not need to install it.
  • @mui/styled-engine-sc: a similar wrapper, but specifically tailored for styled-components. You must install and implement this package to use styled-components with Material UI.

These two packages implement the same interface, making them interchangeable.

Bundler configuration

By default, @mui/material has @mui/styled-engine as a dependency. To use styled-components, you need to configure your bundler to replace it with @mui/styled-engine-sc.

With yarn

If you're using yarn, you can configure it using a package resolution:

package.json
 {
   "dependencies": {
-    "@mui/styled-engine": "latest"
+    "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest"
   },
+  "resolutions": {
+    "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest"
+  },
 }

Configuration with Vite and Vitest

If you are using Vite with Vitest for testing, you may encounter issues with MUI v7+ when using styled-components. This is due to ESM/CJS compatibility issues with styled-components.

To resolve this, add the following configuration to your vite.config.ts:

Option 1: Using fallbackCJS (simpler, but slower)

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

export default defineConfig({
  test: {
    environment: 'jsdom',
    globals: true,
    server: {
      deps: {
        fallbackCJS: true,
      },
    },
  },
  plugins: [react()],
});
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  test: {
    environment: 'jsdom',
    globals: true,
    server: {
      deps: {
        inline: [
          '@mui/material',
          '@mui/system',
          '@mui/styled-engine',
          '@mui/icons-material',
          // Add other MUI packages you're using, such as:
          // '@mui/x-date-pickers',
          // '@mui/x-data-grid',
        ],
      },
    },
  },
  plugins: [react()],
});

The inline option provides better performance and is the recommended approach for most projects.

With npm

Because package resolutions aren't available with npm, you must update your bundler's config to add this alias. The example below shows how to do this with webpack:

webpack.config.js
 module.exports = {
   //...
+  resolve: {
+    alias: {
+      '@mui/styled-engine': '@mui/styled-engine-sc'
+    },
+  },
 };

For TypeScript, you must also update the tsconfig.json as shown here:

tsconfig.json
 {
   "compilerOptions": {
+    "paths": {
+      "@mui/styled-engine": ["./node_modules/@mui/styled-engine-sc"]
+    }
   },
 }

Next.js

next.config.js
+const withTM = require('next-transpile-modules')([
+  '@mui/material',
+  '@mui/system',
+  '@mui/icons-material', // If @mui/icons-material is being used
+]);

+module.exports = withTM({
 webpack: (config) => {
   config.resolve.alias = {
     ...config.resolve.alias,
+    '@mui/styled-engine': '@mui/styled-engine-sc',
    };
    return config;
  }
+});