RTL support

Build right-to-left interfaces with Untitled UI React. Supports Arabic, Hebrew, Persian, and other RTL languages using CSS logical properties.

Right-to-left support

Untitled UI React supports right-to-left (RTL) layouts for languages like Arabic, Hebrew, and Persian. Our components use CSS logical properties that automatically adapt based on the document direction.

Switch between English and Arabic to see how the layout mirrors automatically:

تم نشر المقال

تم نشر هذا المقال بنجاح. سيتمكن أعضاء الفريق من تعديل هذا المقال وإعادة نشر التغييرات.

Notice how the close button, toggle switches, button order, and text alignment all mirror correctly. This is handled by CSS logical properties — no JavaScript direction detection needed.

How it works

Traditional CSS properties like margin-left, padding-right, and left are physical — they always refer to the same side regardless of text direction. CSS logical properties like margin-inline-start, padding-inline-end, and inset-inline-start are directional — they adapt to the document's dir attribute.

Tailwind CSS 4 provides logical property utilities:

Physical (LTR only)Logical (LTR + RTL)CSS property
ml-4ms-4margin-inline-start
mr-4me-4margin-inline-end
pl-4ps-4padding-inline-start
pr-4pe-4padding-inline-end
left-0start-0inset-inline-start
right-0end-0inset-inline-end
text-lefttext-starttext-align: start
text-righttext-endtext-align: end
rounded-l-lgrounded-s-lgborder-start-start-radius
rounded-r-lgrounded-e-lgborder-start-end-radius
border-lborder-sborder-inline-start
border-rborder-eborder-inline-end

Symmetrical utilities like px-4, mx-4, p-4, and m-4 apply to both sides and work correctly in RTL without changes.

Setting up RTL

Set the dir attribute

Add dir="rtl" to your <html> element or any container:

<html lang="ar" dir="rtl">

For dynamic direction switching, use React state:

<html lang={locale} dir={direction}>

Add I18nProvider for React Aria

React Aria components (modals, popovers, tooltips) render in portals outside your DOM tree. They need I18nProvider to inherit the correct direction:

import { I18nProvider } from "react-aria";
 
function App({ children }) {
    return (
        <I18nProvider locale="ar">
            {children}
        </I18nProvider>
    );
}

This ensures portal-based components render with the correct text direction and locale.

Migrate classes with the CLI

Use our CLI to automatically convert physical direction classes to logical properties across your project:

npx untitledui@latest migrate rtl --dry-run
npx untitledui@latest migrate rtl

The CLI transforms ml- to ms-, pr- to pe-, left- to start-, rounded-l- to rounded-s-, and more. Run with --dry-run first to preview changes.

What the CLI migrates

The migrate rtl command handles these conversions:

Direct replacements

These render identically in LTR and automatically mirror in RTL:

CategoryBeforeAfter
Margin leftml-*ms-*
Margin rightmr-*me-*
Padding leftpl-*ps-*
Padding rightpr-*pe-*
Position leftleft-*start-*
Position rightright-*end-*
Border radius leftrounded-l-*rounded-s-*
Border radius rightrounded-r-*rounded-e-*
Border radius top-leftrounded-tl-*rounded-ss-*
Border radius top-rightrounded-tr-*rounded-se-*
Border radius bottom-leftrounded-bl-*rounded-es-*
Border radius bottom-rightrounded-br-*rounded-ee-*
Border leftborder-lborder-s
Border rightborder-rborder-e
Text align lefttext-lefttext-start
Text align righttext-righttext-end
Float leftfloat-leftfloat-start
Float rightfloat-rightfloat-end

RTL variant additions

These add an rtl: counterpart that only activates when dir="rtl" is set:

CategoryBeforeAfter
Slide in from rightslide-in-from-rightslide-in-from-right rtl:slide-in-from-left
Slide in from leftslide-in-from-leftslide-in-from-left rtl:slide-in-from-right
Translate Xtranslate-x-4translate-x-4 rtl:-translate-x-4
Negative translate X-translate-x-4-translate-x-4 rtl:translate-x-4
Space Xspace-x-4space-x-4 rtl:space-x-reverse
Divide Xdivide-xdivide-x rtl:divide-x-reverse
Gradient to rightbg-linear-to-rbg-linear-to-r rtl:bg-linear-to-l
Gradient to leftbg-linear-to-lbg-linear-to-l rtl:bg-linear-to-r

Safe by design: These changes don't affect LTR layouts. ms-4 renders identically to ml-4 in LTR mode — it only differs when dir="rtl" is set.

Directional icons

Icons like arrows and chevrons may need to flip in RTL when they represent navigation direction (e.g., "next" or "previous").

If you're using @untitledui/icons, you can import RTL-aware icon variants that flip automatically based on the document direction:

Physical iconRTL-aware iconUse case
ArrowRightArrowNext"Next" navigation, "forward" action
ArrowLeftArrowPrevious"Previous" navigation, "back" action
ChevronRightChevronNextPagination next, submenu indicator
ChevronLeftChevronPreviousPagination previous, breadcrumb separator
ChevronRightDoubleChevronNextDoubleJump to last page
ChevronLeftDoubleChevronPreviousDoubleJump to first page

Setup

These icons use a data-rtl-flip attribute to mark themselves as flippable. To activate the flip, add this one line to your globals.css:

[data-rtl-flip]:dir(rtl) { transform: scaleX(-1); }

The :dir(rtl) pseudo-class matches any element inside a dir="rtl" context. When the document is LTR, the selector doesn't match and the icon renders normally. When RTL, scaleX(-1) mirrors the icon horizontally. No JavaScript, no runtime cost.

Usage

import { ArrowNext, ChevronPrevious } from "@untitledui/icons";
 
// Flips automatically in RTL — no extra props or classes needed
<Button iconTrailing={ArrowNext}>Next</Button>
<Button iconLeading={ChevronPrevious}>Previous</Button>

Using a different icon library

If you're not using @untitledui/icons, you can flip icons manually with Tailwind's rtl: variant:

<ArrowRight className="rtl:-scale-x-100" />

When NOT to flip

Not all directional icons should flip. Icons representing fixed concepts should keep their original direction — use the physical icon name for those:

  • External links (ArrowUpRight) — always points up-right
  • Play buttons — always points right
  • Reply/forward — follows email convention, not text direction
  • Download/upload — vertical, direction-independent

Testing in Storybook

Our Storybook setup includes an RTL toggle button in the toolbar. Clicking it:

  1. Sets dir="rtl" on the story canvas
  2. Switches React Aria's I18nProvider to Arabic locale
  3. All components mirror automatically

This is configured in .storybook/wrapper.tsx using the storybook-addon-rtl package.

FAQs

Please refer to our frequently asked questions page for more.

Only if you want RTL support. The logical equivalents (ms-, ps-) render identically in LTR mode, so migrating is safe and backwards-compatible. Use npx untitledui@latest migrate rtl --dry-run to preview what changes.

Symmetrical utilities like px-4, mx-4, p-4, and m-4 apply to both sides and work correctly in RTL without any changes. Only single-side utilities (ml-, mr-, pl-, pr-) need migration.

No. Logical properties like ms-4 produce the exact same CSS as ml-4 in LTR mode (margin-inline-start: 1rem = margin-left: 1rem when dir="ltr"). The only difference is in RTL mode.

Slide animations like slide-in-from-right need an rtl: variant (rtl:slide-in-from-left) because CSS transforms don't have logical equivalents. The CLI adds these automatically.

Yes. React Aria has built-in RTL support. Wrap your app with and all React Aria components (modals, popovers, date pickers, etc.) will render correctly in RTL.

Yes. Add dir="rtl" to any container element. CSS logical properties inherit the direction from the nearest ancestor with a dir attribute. Wrap that section with for React Aria components within it.