Skip to Content

Arabic, Persian & RTLGuide9 min read

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.

By Gravity EditorialPublished Updated
A rising row of chrome and red chart candlesticks between two navy curtains.

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.

  1. Declare lang and dir on the html element, in markup rather than CSS. Language and direction are separate declarations.
  2. Isolate every Latin fragment — handles, brand names, tickers, prices — or "@handle" renders as "handle@".
  3. Arabic type needs its own settings: zero letter-spacing, a taller line height, and the Arabic face named directly in the font stack.
  4. Arabic and Persian are separate editions: different letters, usually different digits, each on its own address and linked with hreflang.

What reading natively means

Definition

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 glossary

Setting 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>
An Arabic page: direction declared once, on the root; each left-to-right fragment isolated.

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.

Without isolation

تابعني على @yourhandle

“@” lands on the wrong side
With <bdi>

تابعني على @yourhandle

reads as written
Without isolation the neutral @ takes the paragraph's right-to-left direction and lands on the wrong side of the handle. Isolated, the handle renders as one left-to-right unit.

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;
}
A sketch: Latin face first, Arabic face second, fallbacks after; the Arabic settings scoped by language.

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/">
The same block of links goes in the head of every edition.

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

Common right-to-left failures on Arabic and Persian pages
What breaksWhyFix
"@handle" shows as "handle@"The @ is neutral and takes the paragraph's directionWrap the handle in bdi, or give it dir="auto"
Quotation marks swap endsNeutral punctuation at the edge of a Latin runIsolate the quoted fragment
A ticker or price splits from its labelLatin letters and digits form their own runsWrap them in dir="ltr"
Arabic letters look pulled apartLetter-spacing tuned for Latin display typeSet letter-spacing to 0 for Arabic and Persian
Wrapped headlines collideA Latin display line height near 1About 1.3 for display, 1.4 for titles
Arabic renders in ArialA generated fallback face sits before the Arabic faceName the families directly, Latin then Arabic
Margins and arrows on the wrong sidePhysical left and right in the CSSLogical properties; mirror directional icons only
Search shows the wrong editionMissing or one-way hreflangEvery 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?
Add lang="ar" and dir="rtl" to the html element, in markup rather than CSS. Lay the page out with CSS logical properties so spacing follows the direction, isolate Latin fragments such as handles and tickers, and set Arabic type with no letter-spacing and a taller line height.
Why does @username appear as username@ in Arabic text?
The @ is a neutral character. Between Arabic text and a Latin name it takes the paragraph's right-to-left direction and moves to the far end of the name. Wrapping the handle in a bdi element, or giving it dir="auto", isolates it so it renders as one left-to-right unit.
Is a Persian website the same as an Arabic one?
No. Both run right-to-left in the same script, but Persian adds four letters, uses different forms of yeh and kaf, and usually writes its own digits. Build them as separate editions, each with its own address, consistent letters and one digit system.
How do I use hreflang for Arabic and English pages?
Put a link element for every edition in the head of every edition — hreflang="en", hreflang="ar", hreflang="fa" — plus an x-default for everyone else. Each page must list itself and all the others; Google ignores annotations that are not returned.
Which font should I use for an Arabic website?
A face designed for the script, named directly in the font stack after your Latin face, so no generated fallback catches Arabic letters first. Gravity uses Vazirmatn, an open-source Persian and Arabic typeface with a variable version; its thin weights suit a light design.

Sources

First-party figures are Gravity's own observations of its product. External sources were read on the date shown.

  1. What Gravity learned building right-to-left sites — Gravity

    Gravity, first-party · From Gravity's own type and layout rules: isolation of Latin fragments, zero tracking and taller line heights for Arabic, the font-fallback trap, Vazirmatn, the language switch, and one address per language.

  2. Structural markup and right-to-left text in HTML — W3C Internationalization

    Standard · read 28 September 2026

  3. Inline markup and bidirectional text in HTML — W3C Internationalization

    Standard · read 28 September 2026

  4. Unicode Standard Annex #9: Unicode Bidirectional Algorithm — Unicode Consortium

    Standard · read 28 September 2026

  5. Arabic & Persian Layout Requirements — W3C

    Standard · read 28 September 2026 · A W3C Group Draft Note.

  6. CSS logical properties and values — MDN Web Docs

    Documentation · read 28 September 2026

  7. letter-spacing — MDN Web Docs

    Documentation · read 28 September 2026

  8. Bidirectionality — Material Design (Google)

    Documentation · read 28 September 2026

  9. Vazirmatn — Vazirmatn project, GitHub

    Documentation · read 28 September 2026

  10. Tell Google about localized versions of your page — Google Search Central

    Documentation · read 28 September 2026

Terms in this article

Written by

Gravity Editorial

The team that builds Gravity

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.

  1. 01

    Websites & presenceGuide8 min read

    Why an IB needs a website, not just a social feed

    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.

  2. 02

    The IB businessGuide7 min read

    What is an introducing broker (IB)? How the model works

    The referral business behind most retail forex brokers — what an IB does, how they are paid, and what makes the business last.

  3. 03

    Audience & measurementGuide9 min read

    How to read a trading audience honestly

    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.

Start

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.