Skip to content

How to Fix Arabic RTL Layout Issues in Lovable

To fix Arabic RTL in a Lovable project, set dir="rtl" and lang="ar" on the html element, replace left and right Tailwind classes with logical ones such as ms-, pe- and text-start, add rtl: variants for icons and transforms, wrap mixed numbers and English in bdi, and load an Arabic font. The steps below include the code.

Last updated:

What is going wrong

Lovable generates React projects styled with Tailwind CSS. Those projects are written left to right by default, and we found no RTL guidance in Lovable's official docs index when we checked on 5 November 2026. So when you ask for Arabic, you usually get Arabic words inside an English layout.

The typical symptoms: the logo on the left, chevrons pointing the wrong way, cards with uneven spacing, a drawer menu sliding in from the wrong side, and phone numbers whose digits or plus sign jump around. Here is the same component broken and fixed:

قبل: الصفحة بدون dir
اكتب اسمكإرسال ←
بعد: dir="rtl" وخصائص منطقية
اكتب اسمكإرسال ←
عرض حيّ يرسمه متصفحك الآن، وليس لقطة شاشة.

Every fix below can be pasted as code if you edit files, or given to Lovable as a prompt. Work in order: direction first, because the others depend on it.

Step 1: set the direction on the document

Open index.html at the project root and set both attributes on the html tag. lang helps screen readers and search engines; dir flips the layout.

index.html
<!doctype html>
<html lang="ar" dir="rtl">
  <head>
    <meta charset="UTF-8" />
    <title>متجر العود</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

If the app switches languages at runtime, set the attributes from React instead, so English pages flip back:

src/hooks/useDocumentDirection.ts
import { useEffect } from "react";

export function useDocumentDirection(lang: "ar" | "en") {
  useEffect(() => {
    document.documentElement.lang = lang;
    document.documentElement.dir = lang === "ar" ? "rtl" : "ltr";
  }, [lang]);
}

Projects using shadcn/ui components are built on Radix primitives, which read direction from a provider. Wrap the app so dropdowns, sliders and menus open correctly:

src/App.tsx
import { DirectionProvider } from "@radix-ui/react-direction";

export default function App() {
  return (
    <DirectionProvider dir="rtl">
      <Routes />
    </DirectionProvider>
  );
}

Step 2: replace physical classes with logical ones

Classes like ml-4, pr-6, left-0 and text-left are tied to physical sides, so they stay put when the direction flips. Tailwind (version 3.3 and later) has logical equivalents that follow the reading direction:

Physical (breaks in RTL)Logical (works both ways)
ml-4 / mr-4ms-4 / me-4
pl-6 / pr-6ps-6 / pe-6
left-0 / right-0start-0 / end-0
text-left / text-righttext-start / text-end
rounded-l-lg / rounded-r-lgrounded-s-lg / rounded-e-lg
border-l-4 / border-r-4border-s-4 / border-e-4

A search across src/ for ml-, mr-, pl-, pr-, left-, right- and text-left finds most offenders. A card before and after:

Logical Tailwind classes
// Before
<div className="flex items-center pl-6 border-l-4 border-amber-500">
  <img src={logo} className="mr-3 h-8" />
  <p className="text-left">قهوة مختصة</p>
</div>

// After
<div className="flex items-center ps-6 border-s-4 border-amber-500">
  <img src={logo} className="me-3 h-8" />
  <p className="text-start">قهوة مختصة</p>
</div>

For custom CSS outside Tailwind, use the logical properties directly:

Logical CSS properties
.sidebar {
  margin-inline-start: 1rem;   /* not margin-left */
  padding-inline-end: 1.5rem;  /* not padding-right */
  inset-inline-start: 0;       /* not left: 0 */
  border-inline-start: 4px solid var(--accent);
  text-align: start;           /* not text-align: left */
}

Step 3: use rtl: variants where logic is not enough

Some things have no logical class: horizontal transforms, animations, and the gap utilities that rely on margin. Tailwind's rtl: and ltr: variants apply a class only in one direction.

rtl: variants
{/* A drawer that slides in from the reading side */}
<aside className="fixed inset-y-0 start-0 w-72 -translate-x-full rtl:translate-x-full data-[open=true]:translate-x-0">
  ...
</aside>

{/* space-x uses margins; reverse it in RTL */}
<nav className="flex space-x-4 rtl:space-x-reverse">
  <a href="/">الرئيسية</a>
  <a href="/menu">المنيو</a>
</nav>

gap-4 is direction-neutral and usually simpler than space-x-4 plus rtl:space-x-reverse. Prefer gap in flex and grid layouts.

Step 4: mirror only the icons that show direction

Arrows, chevrons, "back" icons and progress indicators should flip. Logos, play buttons, checkmarks, search glasses, clocks and brand icons should not. With lucide-react icons, which Lovable projects commonly use, add a flip only in RTL:

Mirroring icons
import { ChevronRight, ArrowRight, Check } from "lucide-react";

<button className="inline-flex items-center gap-2">
  التالي
  <ArrowRight className="h-4 w-4 rtl:-scale-x-100" />
</button>

{/* Breadcrumb separator flips */}
<ChevronRight className="h-4 w-4 rtl:-scale-x-100" />

{/* A checkmark keeps its shape */}
<Check className="h-4 w-4" />

Step 5: isolate numbers and English with bdi

When Arabic text contains a price, a phone number with a plus sign, an order code or an English brand, the browser's bidirectional algorithm can move symbols to the wrong end. Wrap these pieces in <bdi>, and use dir="ltr" on inputs that must be typed left to right:

قبل: نص مختلط بلا عزل

اطلب الآن عبر Apple Pay بسعر 49 ريال (شامل VAT).

بعد: dir=rtl مع <bdi> للمقاطع اللاتينية

اطلب الآن عبر Apple Pay بسعر 49 ريال (شامل VAT).

عرض حيّ يرسمه متصفحك الآن، وليس لقطة شاشة.
bdi and dir
<p>
  رقم الطلب <bdi>#A-1042</bdi> بقيمة <bdi>250 ر.س</bdi>،
  للتواصل: <bdi dir="ltr">+966 55 123 4567</bdi>
</p>

<label htmlFor="phone">رقم الجوال</label>
<input id="phone" type="tel" dir="ltr" className="text-end" placeholder="05xxxxxxxx" />

{/* User-generated text of unknown language */}
<p dir="auto">{review.text}</p>

Step 6: load an Arabic font

The system fallback rarely suits Arabic. Load a typeface designed for it and give body text more line height:

قبل: خط النظام الافتراضي وتباعد ضيق

خطّ عربي واضح يرفع الثقة ويسهّل القراءة على الجوال.

بعد: خط مصمم للعربية وتباعد 1.8

خطّ عربي واضح يرفع الثقة ويسهّل القراءة على الجوال.

عرض حيّ يرسمه متصفحك الآن، وليس لقطة شاشة.
Arabic font
/* src/index.css */
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@400;500;700&display=swap");

:root[dir="rtl"] body {
  font-family: "IBM Plex Sans Arabic", system-ui, sans-serif;
  line-height: 1.75;
}

Then add it to tailwind.config under theme.extend.fontFamily if you want a font-arabic utility.

Prompt to give Lovable instead

If you prefer not to edit files, paste this into Lovable. Be specific, because a vague "make it Arabic" usually only changes text alignment:

For LovableTry it in Uttra

Convert the whole app to Arabic right-to-left. Set lang="ar" and dir="rtl" on the html element and wrap the app in Radix DirectionProvider dir="rtl". Replace every ml/mr/pl/pr/left/right/text-left/rounded-l/border-l class with its logical equivalent (ms/me/ps/pe/start/end/text-start/rounded-s/border-s). Add rtl:-scale-x-100 to arrow and chevron icons only. Wrap prices, phone numbers and order codes in bdi. Load IBM Plex Sans Arabic with line-height 1.75.

Afterwards, check the result on a phone width and work through the test in our guide to real RTL support. The Arabic version of this guide is there for Arabic-speaking teammates.

When to choose Uttra instead

These fixes work, and if your project is mostly English with a few Arabic pages, they are all you need. If Arabic is your main language and you would rather not repeat this pass every time a new screen is generated, an Arabic-first builder avoids the problem at the source. See our Lovable alternative for Arabic for a fair side-by-side.

Frequently asked questions

A short request like "make it Arabic" often gets read as a translation task. The text changes, the layout does not. Name the specific changes: dir and lang on html, logical classes, mirrored icons, bdi for numbers and an Arabic font, as in the prompt above.

Related pages