How to Implement RTL Support in Material-UI Using the Stylis Plugin

To implement RTL support in Material-UI, configure your theme with direction: 'rtl' and create an Emotion cache that includes the stylis-plugin-rtl plugin, then wrap your application with both CacheProvider and ThemeProvider.

Material-UI (MUI) uses Emotion as its styling engine, processing CSS through the Stylis preprocessor at runtime. To implement RTL support in Material-UI using the Stylis plugin, you must configure both the theme direction and the Emotion cache to automatically mirror physical CSS properties for right-to-left languages.

How RTL Works in Material-UI

MUI provides two complementary mechanisms that work together to enable RTL support:

Mechanism Purpose Source Location
theme.direction Sets the logical direction ('ltr' or 'rtl') on the theme. Components using logical CSS properties reference this value. packages/mui-material/src/theme/defaultTheme.ts
stylis-plugin-rtl A Stylis plugin injected into Emotion's cache that rewrites CSS rules to flip physical properties (margin-left, right, etc.) when the direction is RTL. packages/mui-styles/src/cache.ts

The plugin operates at the cache level, meaning all generated styles—including custom styled components—are transformed without requiring component-level changes.

Step-by-Step Implementation

Install Required Dependencies

Install Material-UI, Emotion, and the RTL plugin:

npm install @mui/material @emotion/react @emotion/cache stylis-plugin-rtl

Create an RTL-Enabled Emotion Cache

Create a cache instance that includes the Stylis RTL plugin. This configuration mirrors the approach used internally in packages/mui-styles/src/cache.ts:

import createCache from '@emotion/cache';
import rtlPlugin from 'stylis-plugin-rtl';

export const rtlCache = createCache({
  key: 'mui-rtl',
  stylisPlugins: [rtlPlugin],
});

The key property ensures this cache does not clash with default Emotion caches, while stylisPlugins array injects the RTL transformation logic.

Configure the MUI Theme for RTL

Set the direction property when creating your theme. This value is defined in packages/mui-material/src/theme/defaultTheme.ts and processed by packages/mui-material/src/theme/createTheme.ts:

import { createTheme } from '@mui/material/styles';

const theme = createTheme({
  direction: 'rtl',
  // Additional customizations (palette, typography, etc.)
});

Wrap Your Application with Providers

Combine the cache and theme providers at your application root. This pattern ensures all child components receive the RTL-transformed styles:

import * as React from 'react';
import { CacheProvider } from '@emotion/react';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { rtlCache } from './rtlCache';
import { theme } from './theme';
import App from './App';

export default function Root() {
  return (
    <CacheProvider value={rtlCache}>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <App />
      </ThemeProvider>
    </CacheProvider>
  );
}

CssBaseline automatically respects the theme direction, setting the HTML dir attribute and adjusting global styles accordingly.

Verify RTL with Custom Styled Components

Custom components created with the styled API automatically inherit RTL support because they use the same Emotion cache. As implemented in packages/mui-material/src/styles/experimentalStyled.ts, physical properties are mirrored without additional code:

import { styled } from '@mui/material/styles';
import Button from '@mui/material/Button';

const FancyButton = styled(Button)(({ theme }) => ({
  // In RTL mode, margin-left becomes margin-right automatically
  marginLeft: theme.spacing(2),
  padding: '8px 16px',
}));

export default function Demo() {
  return <FancyButton>مرحبا بالعالم</FancyButton>;
}

Key Source Files and Architecture

Understanding the underlying implementation helps debug edge cases:

Summary

  • Use stylis-plugin-rtl to automatically mirror physical CSS properties at the Emotion cache level.
  • Set direction: 'rtl' in your MUI theme to enable logical property support and global direction context.
  • Wrap your app with both CacheProvider (supplying the RTL cache) and ThemeProvider (supplying the RTL theme).
  • No component changes required: Custom styled components and MUI components automatically receive RTL styles because the transformation happens during CSS generation in packages/mui-material/src/styles/experimentalStyled.ts.

Frequently Asked Questions

What is the difference between theme.direction and stylis-plugin-rtl?

theme.direction sets the logical direction property in the MUI theme, which components use to adjust behavior and logical CSS properties. stylis-plugin-rtl is a CSS preprocessor plugin that physically mirrors directional properties (like margin-left becoming margin-right) at the Emotion cache level. You need both working together for complete RTL support.

Do I need to modify individual components to support RTL?

No. Because the RTL transformation occurs at the Emotion cache level (as implemented in packages/mui-styles/src/cache.ts), both MUI components and custom styled components automatically receive mirrored styles. The architecture isolates RTL concerns to theme and cache configuration.

Can I use RTL with Styled Components instead of Emotion?

While MUI primarily uses Emotion as its default styling engine, the same stylis-plugin-rtl approach works with Styled Components because both libraries use Stylis as their CSS preprocessor. You would configure the Stylis plugin in your Styled Components setup rather than using Emotion's createCache.

How do I handle mixed LTR and RTL content in the same application?

For applications requiring both directions, create separate Emotion caches (one with stylis-plugin-rtl and one without) and switch between them using CacheProvider at the appropriate component tree level. Alternatively, nest ThemeProvider instances with different direction values, though you must ensure the cache matches the theme direction for that subtree.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →