How to build a proper Arabic (RTL) website
I recently posted a command inside an Arabic sentence on X, and part of it displayed wrongly: the slash in /bye moved after the word, so it read “bye/”. The problem is not the platform alone. It hits any site that mixes Arabic and English without care. This guide shows how to build an Arabic site properly from the start.
1. Start with lang and dir
The first line of your page sets language and direction. Browsers, screen readers and search engines depend on it:
<html lang="ar" dir="rtl">Set the direction with the dir attribute in HTML, not in CSS alone, because it is part of the meaning of the page. The attribute also isolates the text inside the element from the text around it.
2. Logical properties instead of left and right
If you write margin-left, you must rewrite everything when the direction flips. Logical properties follow the page direction automatically, so you write the rule once. According to MDN, margin-inline-start equals margin-left on left-to-right pages and margin-right on right-to-left pages.
| Physical property | Logical equivalent |
|---|---|
| margin-left / margin-right | margin-inline-start / margin-inline-end |
| padding-left / padding-right | padding-inline-start / padding-inline-end |
| border-left | border-inline-start |
| text-align: left | text-align: start |
| float: left | float: inline-start |
| left: 0 | inset-inline-start: 0 |
| width / height | inline-size / block-size |
A common trap: writing margin: 0 after a logical property resets it. Use the logical shorthands consistently, or put the logical property last. Flexbox and Grid already follow the direction, so setting direction: rtl flips the order of items with no extra work.
.card {
margin-inline-start: 1rem;
padding-inline: 1rem 2rem; /* start end */
text-align: start;
border-inline-start: 4px solid var(--accent);
}In modern Tailwind you get the equivalents ms-4, me-4, ps-4, pe-4 and border-s-2. Check your version's docs for the exact names.
3. Mixed text: the source of most bugs
When you put an English part (a command, a link, a product name) inside an Arabic sentence, the Unicode algorithm tries to guess the direction of punctuation and symbols, and it can guess wrong. Example: اكتب /bye للخروج.
The fix is to isolate the English part. According to the W3C: if you know the direction, add the dir attribute. If you do not (text from a database or a user), use dir="auto" or the <bdi> element.
<p>Arabic text <bdi dir="ltr">ollama run gemma4:e2b</bdi> more Arabic text.</p>
<!-- user-generated text, direction unknown -->
<p>Name: <bdi>{userName}</bdi></p>Do not rely on unicode-bidi: isolate in CSS alone for meaning. MDN notes that CSS may be ignored, while the <bdi> element carries the meaning.
Where you cannot use HTML: in social posts and plain text, put the English part on its own line. To keep it inside the sentence, surround it with the characters U+2066 (LRI) and U+2069 (PDI), which isolate left-to-right text.
Always left-to-right: email addresses, links, phone numbers and terminal commands. Give them dir="ltr".
4. Icons and images
- Mirror: back and next arrows, dropdown arrows, and anything that shows navigation direction.
- Do not mirror: logos, photos, clocks, checkmarks and play buttons.
[dir="rtl"] .icon-arrow { transform: scaleX(-1); }5. Fonts and spacing
- Pick a real Arabic font such as Cairo, Tajawal or IBM Plex Sans Arabic, and self-host it: faster, and kinder to visitor privacy.
- Load the real weights (400 and 700) so the browser does not fake a bold that distorts letters.
- Do not use letter-spacing on Arabic: it breaks the joins between letters.
- Do not use italics for emphasis, since they are not part of Arabic writing. Use weight or colour.
- Increase line height (about 1.7 to 1.9 for paragraphs) because Arabic letters extend above and below the line.
6. Numbers and dates
Number habits differ across Arab countries: some prefer Arabic-Indic digits and some Western digits. Let the user or their country decide, and format with Intl, no libraries needed:
new Intl.NumberFormat('ar-EG').format(1234.5)new Intl.NumberFormat('ar-EG-u-nu-latn').format(1234.5)new Intl.DateTimeFormat('ar-SA-u-ca-islamic-umalqura').format(new Date())The first gives Arabic-Indic digits, the second forces Western digits, and the third gives a Hijri (Umm al-Qura) date. Test what you see before you publish.
7. Forms and inputs
<!-- free text: direction follows what the user types -->
<input type="text" dir="auto">
<!-- always left-to-right -->
<input type="email" dir="ltr">
<input type="tel" dir="ltr">Common mistakes and fixes
| Symptom | Cause | Fix |
|---|---|---|
| An element sticks to the wrong side | A fixed margin-left or left | Logical properties (inline-start / inline-end) |
| Punctuation jumps somewhere odd | Latin text inside an Arabic sentence with no isolation | bdi, a dir attribute, or a separate line |
| Arabic letters look separated | letter-spacing on Arabic text | Remove letter-spacing |
| A phone number or link is reversed | Direction not set | dir="ltr" on the element |
| An arrow points the wrong way | A directional icon was not mirrored | scaleX(-1) inside [dir="rtl"] |
| Bold text looks distorted | Fake bold for a font with no bold weight | Load the real font weight |
Pre-launch checklist
- Toggle dir on the html element between rtl and ltr in the developer tools, and confirm the whole layout flips.
- Test this sentence in your pages: اكتب /bye ثم Ctrl+C (أو Enter) للخروج.
- Put in a long link and a long English name, and watch for horizontal overflow.
- Open the page on a real phone, not just the emulator.
- Check that directional icons flipped and logos did not.
FAQ
Do I need a separate CSS file for Arabic?
No, if you use logical properties. You write the rules once and they work in both directions.
Is direction: rtl in CSS enough?
It works, but setting dir in HTML is better because it is part of the content's meaning, which is what the W3C recommends.
Can I just translate the interface and mirror it?
No. Test real Arabic text, numbers and dates, and the font. Automatic mirroring is not enough.
A new tool every day
I post a free AI tool on X every day, and all sources and paths live in the library.