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:
packages/mui-material/src/theme/defaultTheme.ts: Defines the defaultdirection: 'ltr'value and theme structure.packages/mui-material/src/theme/createTheme.ts: Merges user configuration (including RTL direction) with the default theme.packages/mui-styles/src/cache.ts: Provides utilities for creating Emotion caches; the RTL implementation follows this pattern by injectingstylisPlugins.packages/mui-material/src/ThemeProvider/ThemeProvider.tsx: Injects the theme (and thusdirection) into the React context tree.packages/mui-material/src/CssBaseline/CssBaseline.tsx: Applies global RTL styles based on the theme direction.packages/mui-material/src/styles/experimentalStyled.ts: ThestyledAPI that consumes the RTL-enabled Emotion cache.
Summary
- Use
stylis-plugin-rtlto 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) andThemeProvider(supplying the RTL theme). - No component changes required: Custom
styledcomponents and MUI components automatically receive RTL styles because the transformation happens during CSS generation inpackages/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →