Publishing right-to-left: an Arabic and Persian website that reads natively
Direction is one attribute. Reading natively is everything after it — the handles, tickers, numbers and type that run through an Arabic or Persian page.

The short answer
An Arabic or Persian website reads natively when direction is declared once, in markup — lang and dir="rtl" on the html element — and everything that runs the other way is isolated: handles, brand names, tickers and prices. The type is set for the script rather than borrowed from Latin: no letter-spacing, a taller line height, and the Arabic face named directly in the font stack. Each language is its own edition, linked to the others with hreflang.
- Declare lang and dir on the html element, in markup rather than CSS. Language and direction are separate declarations.
- Isolate every Latin fragment — handles, brand names, tickers, prices — or "@handle" renders as "handle@".
- Arabic type needs its own settings: zero letter-spacing, a taller line height, and the Arabic face named directly in the font stack.
- Arabic and Persian are separate editions: different letters, usually different digits, each on its own address and linked with hreflang.
On this page · 15 sections
- What reading natively means
- Declare language and direction in markup
- Isolate every Latin fragment
- Numbers and tickers stay left-to-right
- Set the type for the script
- No letter-spacing
- More room between lines
- Name the Arabic face in the stack
- Arabic and Persian are two editions
- Mirror the layout, not every icon
- Give each language its own address
- What breaks, and the fix
- Before an Arabic or Persian page goes live
- Questions
- Sources
What reading natively means
Right-to-left (RTL) — A writing direction in which lines start at the right edge and run leftward, as in Arabic and Persian. A right-to-left page mirrors its layout to match.
In the glossarySetting a page to right-to-left takes one attribute. Making it read natively takes everything after that: the Latin fragments that run through Arabic and Persian text, type set for the script, numbers that keep their shape, and an address for each language. The failures are small and very visible — a handle printed backwards, a price split from its label, two lines of a headline colliding — and each one tells the reader the page was built for someone else.
For an introducing broker that is a trust problem, not a cosmetic one. The IB business depends on a referred trader checking the IB's page and trusting what they find there — the reason an IB needs a website, not just a feed. A page that stumbles over its reader's language has not earned that trust. The lessons below come from building Gravity's right-to-left sites1; the rules come from the W3C, MDN and Google's own documentation.
Declare language and direction in markup
Put the language and the direction on the html element. The W3C's guidance is to add dir="rtl" to the html tag whenever a document's overall direction is right-to-left, and not to set base direction with CSS, so the direction holds even when styles do not load2. Declare the language with lang as well, and keep the two apart: a language declaration does not set direction, and a direction does not name a language2.
<!doctype html>
<html lang="ar" dir="rtl">
<body>
<!-- a handle: isolate it, or it renders as "yourhandle@" -->
<p>تابعونا على <bdi>@yourhandle</bdi></p>
<!-- a ticker: always left-to-right -->
<p>الرمز <span dir="ltr">XAUUSD</span></p>
<!-- text from data, direction unknown: let the browser decide -->
<h2 dir="auto">…</h2>
</body>
</html>Lay the page out with CSS logical properties rather than left and right: margin-inline-start instead of margin-left, padding-inline instead of a left and right pair. Logical properties map to physical sides from the writing direction, so one stylesheet serves both editions6.
Isolate every Latin fragment
Every left-to-right run inside right-to-left text must be isolated: handles, brand names, tickers such as XAUUSD, prices, web addresses. Without isolation, "@handle" renders as "handle@" and quotation marks swap ends1.
تابعني على @yourhandle
تابعني على @yourhandle
Text that mixes the two directions is bidirectional text, and browsers order it with the Unicode Bidirectional Algorithm. Letters carry a strong direction. Punctuation and spaces are neutral, and a run of neutrals takes the direction of the strong text around it — or, where the two sides disagree, the direction of the paragraph4. An @ between Arabic text and a Latin handle sits exactly where the sides disagree. It takes the paragraph's right-to-left direction and moves to the far end of the handle. A closing quotation mark or a trailing full stop does the same.
The fix is isolation. When a fragment's direction is known, wrap it in an element with dir set — dir="ltr" for a ticker. When it is not known, as with a name that arrives from data, use dir="auto" or the bdi element, both of which take the direction from the fragment's first strong character3. An isolated fragment is laid out as one unit, and nothing inside it disturbs the text outside. A site built from data rarely knows in advance which way a name runs, which makes dir="auto" the safer default for anything a user supplies.
Numbers and tickers stay left-to-right
Numbers are not mirrored. Material Design's bidirectionality guidance keeps numbers, such as phone numbers, left-to-right inside a right-to-left interface8. A ticker, a price or a spread reads the same way in any language. Wrap each one with dir="ltr" and it will neither split from its label nor pull neighbouring punctuation across.
Set the type for the script
Typographic settings tuned for Latin break Arabic and Persian. Three matter most.
No letter-spacing
Arabic letters join. Tracking that makes a Latin headline look tight and deliberate pulls Arabic letters apart: MDN notes that languages using the Arabic script expect connected letters to stay visually connected, and that letter spacing can make the text look broken7. Gravity tracks its Latin display type tight and drops the tracking to zero wherever the text is Arabic1. Where Arabic must be stretched, the script has its own tool — the kashida, a lengthened join between letters — rather than space between them5.
More room between lines
Arabic and Persian have tall ascenders and deep descenders. A Latin display line height — Gravity's is 0.98 — makes a wrapped Arabic headline collide with itself, the marks of one line touching the letters of the next. Gravity sets about 1.3 for Arabic display type and 1.4 for titles1.
Name the Arabic face in the stack
The quietest failure is in font fallback. A framework's font loader may generate a metric-matched fallback face for a Latin web font; in Gravity's case it was local Arial, declared with no unicode-range. Arial carries Arabic, so a fallback placed ahead of the intended Arabic face catches every Arabic letter first, and the Arabic face never appears1. Name the families directly: the Latin face first, then the Arabic face, then the fallbacks. Latin words in the line — a brand, a handle — keep their own family, and Arabic letters fall through to the Arabic face.
:root {
--font-display: "Space Grotesk", "Vazirmatn",
"Space Grotesk Fallback", system-ui, sans-serif;
}
.display {
font-family: var(--font-display);
letter-spacing: -0.04em;
line-height: 0.98;
}
.display:lang(ar),
.display:lang(fa) {
letter-spacing: 0;
line-height: 1.3;
}Gravity sets Arabic and Persian in Vazirmatn, an open-source Persian and Arabic typeface under the SIL Open Font License, drawn in weights from Thin to Black and also shipped as a variable font9. Its thin end suits a light, linear design: hairline display, light titles1.
For the type itself — choosing an Arabic web font, why tracking breaks joined letters, Persian letters and digits, and the font-fallback trap — see Arabic and Persian typography for the web.
Arabic and Persian are two editions
Arabic and Persian share a script, not a spelling. Persian adds four letters Arabic does not use — پ, چ, ژ and گ — and writes ی and ک where Arabic writes ي and ك: pairs that look alike in some positions but are different characters5. Text typed on the wrong keyboard mixes the two, and a search for one form can miss the other. Keep each edition to its own letters.
Digits differ too. Western digits (0–9) are used in parts of the Arab world such as Algeria and Morocco; Arabic-Indic digits (٠١٢٣٤٥٦٧٨٩) in Egypt, Saudi Arabia and Iraq; extended Arabic-Indic digits (۰۱۲۳۴۵۶۷۸۹) in Iran and Afghanistan5. The two Eastern sets visibly differ at four, five and six. Pick one system per edition and use it everywhere — prices, dates, phone numbers — so a reader never meets two ways of writing the same figure on one page.
Mirror the layout, not every icon
A right-to-left page mirrors its layout: navigation starts from the right, the back arrow points right and the forward arrow left. Icons that show direction mirror with it. Icons that show something else do not. Material Design keeps media playback controls unmirrored, because they refer to the direction of the media being played, and keeps clocks turning clockwise8. A logo is a fixed mark and keeps its orientation.
A language switch is a control, not a sentence. Gravity keeps "EN" first in either direction, so the switch looks and works the same whichever edition a reader lands on1.
Give each language its own address
Each language should be its own edition with its own address, linked to the others with hreflang1. Google reads hreflang from HTML link elements, HTTP headers or a sitemap, and treats the three as equivalent. It ignores the annotations unless both pages point to each other, so each edition lists itself and every alternate; x-default names the page for readers whose language matches none10. Language codes use ISO 639-1 — ar for Arabic, fa for Persian10.
<link rel="alternate" hreflang="en" href="https://example.com/en/">
<link rel="alternate" hreflang="ar" href="https://example.com/ar/">
<link rel="alternate" hreflang="fa" href="https://example.com/fa/">
<link rel="alternate" hreflang="x-default" href="https://example.com/en/">Hreflang tells a search engine which page to show; it does not tell it what language a page is in. Google works that out from the content and does not use hreflang or the lang attribute to detect it10. A page with an Arabic address and English copy will be read as English. Translate the whole edition, including the risk warning, which only protects the people who can read it.
What breaks, and the fix
| What breaks | Why | Fix |
|---|---|---|
| "@handle" shows as "handle@" | The @ is neutral and takes the paragraph's direction | Wrap the handle in bdi, or give it dir="auto" |
| Quotation marks swap ends | Neutral punctuation at the edge of a Latin run | Isolate the quoted fragment |
| A ticker or price splits from its label | Latin letters and digits form their own runs | Wrap them in dir="ltr" |
| Arabic letters look pulled apart | Letter-spacing tuned for Latin display type | Set letter-spacing to 0 for Arabic and Persian |
| Wrapped headlines collide | A Latin display line height near 1 | About 1.3 for display, 1.4 for titles |
| Arabic renders in Arial | A generated fallback face sits before the Arabic face | Name the families directly, Latin then Arabic |
| Margins and arrows on the wrong side | Physical left and right in the CSS | Logical properties; mirror directional icons only |
| Search shows the wrong edition | Missing or one-way hreflang | Every edition lists itself and all the others |
Before an Arabic or Persian page goes live
- lang and dir="rtl" on the html element, in markup.
- Every handle, brand name, ticker and price isolated with bdi, dir="auto" or dir="ltr".
- Layout in logical properties; directional icons mirrored, media controls and logos left as they are.
- Letter-spacing at zero and the line height opened up for Arabic and Persian.
- The Arabic face named directly in the font stack, ahead of any generated fallback.
- One set of letters and one digit system per edition.
- Each edition on its own address, with two-way hreflang and an x-default.
- The risk warning translated, not left in English.
Questions
How do I make a website right-to-left for Arabic?
Why does @username appear as username@ in Arabic text?
Is a Persian website the same as an Arabic one?
How do I use hreflang for Arabic and English pages?
Which font should I use for an Arabic website?
Sources
- What Gravity learned building right-to-left sites — Gravity
- Structural markup and right-to-left text in HTML — W3C Internationalization
- Inline markup and bidirectional text in HTML — W3C Internationalization
- Unicode Standard Annex #9: Unicode Bidirectional Algorithm — Unicode Consortium
- CSS logical properties and values — MDN Web Docs
- letter-spacing — MDN Web Docs
- Bidirectionality — Material Design (Google)
- Vazirmatn — Vazirmatn project, GitHub
- Tell Google about localized versions of your page — Google Search Central
Terms in this article
Gravity Editorial
Written by the people who build Gravity, from what the product does and what building it taught us. Figures come from Gravity's own measurements or from the source cited beside them; nothing on these pages is trading advice. See how we write.
Related in the Journal
A feed is where people find you. A website is where they decide whether to trust you — the one place your offer, your broker and your risk warning sit together.
The referral business behind most retail forex brokers — what an IB does, how they are paid, and what makes the business last.
Follower counts are the vanity figure. What an IB needs before choosing a partner is how engaged an audience is, where it sits, and what nobody has measured yet.
One profile is all Gravity needs to begin.
Give Gravity a public Instagram, TikTok or YouTube profile. It reads it and builds your website in your own language — in minutes, with nothing on it you can't stand behind.
