How to know if your website is really RTL-ready

Run concrete tests for document direction, mixed text, layout, forms, fonts, formats, overflow and keyboard order to judge RTL readiness.

Guide15 min read

An Arabic page with dir="rtl" can still fail every task that matters. The root direction may disappear after navigation, a numeric ID may reorder, a carousel may scroll backward, an empty search field may jump sides when the user types, or a dialog may overflow only after its Arabic error loads.

RTL-ready means more than mirrored. It means the site keeps its direction through real journeys, preserves mixed-direction values, uses direction-aware layout, accepts the right input in each field, fits Arabic typography, follows the market's format rules and remains operable by keyboard.

The tests below are designed to produce evidence. Run them on a critical journey such as checkout, account creation or order lookup, not only on the homepage. A pass should be reproducible. A failure should point toward the layer that owns the fix.

Start with a realistic test fixture#

Before testing, load content that can expose the failures. Short, Arabic-only placeholders make an unfinished implementation look ready.

Your fixture should include:

  • a long Arabic navigation label and multiline error;
  • a digit-leading reference such as 8812-306;
  • the same reference with a Latin prefix, such as REF-8812-306;
  • a phone in your market's format, such as +20 10 1234 5678;
  • an email, URL and a Latin product name ending in punctuation, such as .NET 8;
  • a large price, negative value and percentage;
  • a date with a day above 12;
  • an Arabic name, Latin name and mixed-language user content;
  • loading, empty, invalid, failed and success states.

Run the fixture at the minimum supported viewport, an intermediate width where components wrap and a wide layout. Wait for web fonts and API data. Open menus, dialogs, tooltips, filters and toasts. A route is not RTL-ready merely because its initial desktop state passes.

Record the locale, route, build, browser, operating system and viewport with every result. The browser behavior cited on this page was measured in Chromium 151. Reproduce uncertain native-control or scrolling behavior in the site's actual support matrix rather than assuming every engine is identical.

Test 1: enter the Arabic route directly#

Open a deep Arabic URL in a private session. Refresh it, follow internal links, sign in, sign out and open a second tab. Switch locale on a specific product or order page.

Pass: The URL, visible content and application state follow the product's locale contract through every transition.

Fail: Authentication drops the locale, every language switch returns to the homepage, or a deep Arabic URL initially serves English and changes only after client code runs.

Then inspect the live root:

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

lang identifies the language. dir establishes base direction. One does not imply the other. The HTML dir documentation recommends explicit document direction for RTL content.

Do not accept direction: rtl in CSS as the only evidence. It changes rendering, but in Chromium 151 it does not make an element match :dir(rtl). A component can disagree with a page that only looks RTL. R001 reports a missing or LTR root direction on an Arabic page. R002 reports a missing or contradictory root language.

For public pages, also inspect the Arabic title, description, social metadata, canonical and language alternatives. R003, R004, R005 and R006 cover these locale and metadata failures.

If critical Arabic entry points lose the locale or the live root has the wrong direction, the site is not ready. Fix that baseline before judging spacing.

Test 2: put hostile values inside Arabic sentences#

The browser lays Arabic, Latin text, digits and punctuation out with the Unicode Bidirectional Algorithm. Business values are not automatically treated as indivisible strings.

Render each fixture at the beginning, middle and end of an Arabic sentence. Follow it with punctuation and another number.

Problem

html
<p dir="rtl">رقم المرجع 8812-306</p>

In Chromium 151, the reference displays as 306-8812 after the Arabic label. REF-8812-306 stays intact in the measured context because the Latin prefix establishes a strong LTR run, so a site whose test data only ever uses prefixed references passes this test without being ready for it.

Better when direction is unknown

html
<p dir="rtl">رقم المرجع <bdi>8812-306</bdi></p>

Better when the value is defined as LTR

html
<p dir="rtl">رقم المرجع <span dir="ltr">8812-306</span></p>

A plain span is not enough because it provides no bidi isolation. The W3C inline bidi guidance recommends tightly wrapping opposite-direction phrases.

Do not infer that every numeric-looking token needs the same repair. Slashes, colons, commas and full stops keep digit sequences together after Arabic text in the measured browser; hyphens and spaces do not. The bidirectional text guide has the full table. Apply isolation around the complete semantic value, not around individual digits or punctuation.

Signs and units deserve their own fixtures. In the measured browser, a percentage after Arabic text shows its sign before the digits, while the same value on its own displays as authored, and a negative -7 shows as 7- in both contexts. Whether that display is acceptable depends on the market's formatting rule, but inconsistency between two instances of the same value is a clear defect.

Pass: Phones, emails, URLs, references, product names, percentages and punctuation remain readable while copied values preserve their source data.

Fail: A phone's digit groups reverse, .NET 8 displays as NET 8. with its leading full stop moved to the far end, a reference changes visible order, or final punctuation appears at the wrong end. Phone numbers carry enough traps of their own, including Arabic-Indic digits that reverse inside <bdi>, to have a separate guide.

Do not use copying alone as the test. A value that displays in the wrong bidi order still copies in authored order, and its accessibility-tree text can also remain correct. Test data, visual display and interaction separately. R021 reports unisolated phones, emails and Latin tokens. R024 reports punctuation at the wrong visual end.

Test 3: insert a Latin name next to a count#

This small test exposes whether dynamic strings can affect their neighbors. Use the activity feed, notification or comment count your product actually renders:

html
<p dir="rtl">أضاف Omar 4 صور</p>

In Chromium 151, the 4 joins the name's LTR run and displays between the Arabic verb and Omar, away from the word it counts.

Better

html
<p dir="rtl">أضاف <bdi>Omar</bdi> 4 صور</p>

Pass: Arabic, Latin and digit-leading user names remain contained, and the count stays associated with the intended Arabic words.

Fail: The number crosses the name, punctuation changes sides or two adjacent names merge into one confusing run.

Do not put the entire message inside one dir="auto" element. A message with multiple inserted strings has more than one directional source. Isolate each unknown string individually.

Repeat with an Arabic name, Latin name and user-generated text beginning with digits. This is a better readiness fixture than a hard-coded English brand whose direction never changes.

Test 4: compare logical relationships, not a mirrored screenshot#

Inspect navigation, breadcrumbs, field icons, cards, pagination, toasts and dialogs in both directions. Ask whether start and end roles remain correct. Dropdown menus are a quick tell:

Problem

css
.menu {
  position: absolute;
  left: 0;
}

.menu-item {
  padding-left: 16px;
  text-align: left;
}

On the Arabic route the menu still opens from its trigger's left edge, so a trigger near the right of the header drops a menu that runs off the screen, and its items hug the wrong side.

Better for a menu anchored at inline start

css
.menu {
  position: absolute;
  inset-inline-start: 0;
}

.menu-item {
  padding-inline-start: 16px;
  text-align: start;
}

CSS logical properties map start and end according to direction. In Chromium 151, the first flex, grid and table-row item begins on the right under RTL, and margin-inline-start maps to the right margin.

Physical properties do not mirror. left, margin-left, translateX() and SVG drawings keep their authored geometry. That is correct for genuinely physical meaning such as a compass or media timeline. It is fragile for a logical start or end relationship.

Pass: Components inherit direction, logical start and end relationships work, and physical content stays physical.

Fail: The Arabic route depends on page-specific overrides, icons overlap text, a drawer enters from the wrong edge, or transforms push controls off-screen. R022, R030, R031, R032 and R033 report common physical assumptions.

Readiness is stronger when the fix lives in a shared component or token. A route-level override can hide the same defect in every other consumer.

Test 5: remove every row-reverse RTL patch#

Temporarily inspect or disable row-reverse, CSS order and manual array reversal used only for RTL. A normal flex row already follows the container direction.

In an RTL container, row-reverse reverses the RTL axis again. In Chromium 151, items then lay out left to right in DOM order and Tab moves left to right. The screenshot may look plausible while direction and source order tell different stories.

MDN warns that row-reverse can disconnect visual and DOM order. R081 reports the pattern when it is used to imitate RTL.

Pass: Direction comes from dir, DOM order is logical and CSS layout places items without task-breaking visual reordering.

Fail: Disabling row-reverse destroys the component because it was the only RTL mechanism, or focus jumps between visually distant controls.

Do not repair the mismatch with positive tabindex. It creates a parallel order that becomes fragile when controls appear conditionally or layouts change.

Test 6: use only the keyboard#

Put the mouse away and run the critical journey from the address bar to the confirmation screen. Every step a customer takes should be reachable with Tab, Enter, Space and the arrow keys, including the step where the form rejects their input and the dialog they dismiss on the way.

Visual order and focus order do not have to match every coordinate. They do need to preserve meaning and operation. The WCAG focus-order guidance allows more than one logical sequence when relationships remain clear.

Pass: Focus stays visible, follows the task, reaches translated errors and behaves predictably in overlays.

Fail: Focus jumps across a visually ordered toolbar, lands behind a dialog, disappears after closing a menu or skips a required control.

Inspect the accessibility tree as well. A translated icon button can still expose an English aria-label. An intentional English product title may need lang="en" for correct language processing. R012 reports untranslated attribute text; R080 reports foreign-language runs without language markup.

A site that works only with a mouse is not RTL-ready, even if every component is mirrored.

Test 7: inspect both horizontal edges at hostile widths#

Run the route at the minimum supported width, intermediate wrap points, wide desktop and 200 percent zoom. Open every dynamic surface and wait for fonts and API data.

In Chromium 151, content extending past the left edge of an RTL page adds horizontal scrollable width. Equivalent content past the right edge does not. LTR behaves in the opposite direction.

At each width:

  1. Compare document scrollWidth with clientWidth.
  2. Scroll to both horizontal extremes.
  3. Inspect fixed, sticky and absolutely positioned elements near the left edge.
  4. Trigger multiline validation, menus, dialogs, toasts and tooltips.
  5. Load the longest approved Arabic strings.
  6. Repeat after web fonts load.

Pass: The page has no unexpected horizontal scroll, text remains reachable and overlays fit without covering required content.

Fail: A left-edge child expands the page, a fixed action covers text, or a translated label is clipped inside a fixed-width container.

Do not use overflow-x: hidden on the root as the readiness fix. It can hide the scrollbar while leaving content unreachable. R040, R041, R042 and R043 report overflow, overlap, clipping and fixed-width failures.

Test 8: scroll every horizontal component in both directions#

Carousels, tabs and wide tables can look correct and still have broken controls because their scripts assume positive scrollLeft.

The coordinates are the reason. On an RTL scroller, scrollLeft is 0 at the start and counts down into negative numbers as the content moves toward its end. A "next" handler that adds a positive offset therefore asks to scroll past the start: in Chromium 151 it did nothing on the first slide, and from any later slide it moved backward.

Pass: Previous and next controls reach the correct logical items from start, middle and end. Keyboard, touch and wheel input agree with the control labels.

Fail: Next does nothing at the RTL start, moves backward, or assertions assume that all valid scroll positions are non-negative.

Implement scrolling in logical terms and centralize the direction mapping. Test which item becomes visible rather than only comparing numeric offsets. Browser overscroll details can differ, so verify the component in the supported matrix.

Test 9: edit Arabic and LTR form values#

An Arabic form is not uniformly RTL at the field level. Names, addresses, queries and prose generally use RTL. Phone, email, URL and code values usually remain LTR.

html
<form lang="ar" dir="rtl">
  <label for="company">اسم الشركة</label>
  <input id="company" name="company" dir="rtl" autocomplete="organization">

  <label for="work-email">البريد الإلكتروني للعمل</label>
  <input id="work-email" name="work-email" type="email" dir="ltr" autocomplete="email">
</form>

In Chromium 151, type="tel" is LTR by default, but email, URL, number, search and text controls inherit page direction unless they set one. The email field above would edit right to left without its dir="ltr", and nothing about its type would prevent it.

Work each field through its whole life: empty with its placeholder, focused, half typed, pasted into, corrected in the middle and submitted wrong. Required, format, server and cross-field errors each take a different path to the screen.

Watch dir="auto". An empty auto-direction input resolves LTR in the measured browser, so an Arabic placeholder appears on the left. Typing the first Arabic letter changes the field to RTL and alignment jumps. Use auto only when content direction is genuinely unknown.

Do not rely on lang="ar" to translate native validation bubbles. In Chromium 151 with an English browser interface, a required field on an Arabic page still produced an English built-in message. If Arabic validation text is part of the release requirement, render product-owned messages, associate them with the control and test them in the invalid submission path. Keep the native validity state and focus behavior instead of replacing the entire validation model with decorative text.

Pass: Each field direction matches its data, editing is predictable, errors are Arabic and associated with the correct control.

Fail: Arabic text starts from the left, phone or email edits RTL, placeholder alignment jumps unexpectedly or native validation appears in an unsupported language. R023, R070, R071, R072 and R073 cover common form failures.

Test 10: verify Arabic font coverage and shaping#

Inspect the rendered font for Arabic text in DevTools after web fonts load. A declared family can cover Latin while Arabic falls through to a system font with different width, baseline and line height.

Pass: The intended Arabic-capable font renders consistently, letters remain connected and labels fit at target widths and zoom.

Fail: Arabic uses an unintended fallback, glyphs or marks clip, positive tracking pulls letters apart, or uppercase and italic styles designed for Latin flow into Arabic.

R050 reports measured fallback or a stack with no Arabic-capable family. R051, R054 and R055 cover letter spacing, italic or oblique styling and Latin display treatments. R052 and R053 report cramped line height and undersized body text.

Do not fix a font or geometry problem by shortening accurate translation. Use an Arabic-capable stack, script-appropriate typography and content-driven dimensions.

Test 11: compare formats with a written market rule#

Direction does not select a numbering system, calendar or currency. Define the expected output for the market before judging readiness.

Runtime defaults differ by locale and move between versions: in Chromium 151, Saudi and Egyptian Arabic defaulted to Arabic-Indic digits and generic and Emirati Arabic to Western digits, all on the Gregorian calendar. A ready site does not depend on which of those it gets. It passes numberingSystem and calendar wherever the output is a business requirement.

For example, a UAE booking site that has settled both questions makes them explicit instead of inheriting them from the runtime:

js
const fare = new Intl.NumberFormat("ar-AE", {
  style: "currency",
  currency: "AED",
  numberingSystem: "latn",
});

const departure = new Intl.DateTimeFormat("ar-AE", {
  calendar: "gregory",
  numberingSystem: "latn",
  dateStyle: "full",
});

latn matches the current ar-AE default, and stating it anyway is the point: the site's output no longer depends on which locale data the next runtime ships. The options are one product's decision, not a UAE requirement. Another product may deliberately choose Arabic-Indic digits or another calendar. The readiness test is whether design, content and engineering agree on one documented contract and every output surface follows it.

Test a date above day 12, month names, decimals, thousands, negative amounts, zero, percentages and units. Compare UI, filters, email, export and receipt.

Pass: Formats follow the approved market contract consistently across surfaces and remain readable inside Arabic sentences.

Fail: Digit systems mix in one context, currency belongs to another market, English month names remain, or percent and unit ordering changes between components.

R060, R061, R062, R063 and R064 cover these format failures. A preference is not a bug unless the product contract defines a different requirement, but inconsistency without a reason is a readiness risk.

Test 12: force dynamic and failure states#

An initial screenshot cannot prove readiness. Dynamic states combine content, timing, fonts and geometry in ways isolated component reviews miss.

Force:

  • the skeleton screen giving way to real data;
  • a search with no results, then one with many;
  • a rejected submission, then a corrected one;
  • an API timeout and its retry;
  • a session that expires mid-task;
  • the fallback font swapping for the web font;
  • switching language without a full reload;
  • resizing across a breakpoint while a panel is open.

Pass: Direction, translation, geometry, focus and value order remain correct before and after every transition.

Fail: A server error bypasses the Arabic catalog, a late label creates overflow, direction resets after navigation, or focus disappears after an overlay changes.

Record computed direction, rendered font, bounding boxes and content source before and after the change. The transition that introduces the failure usually identifies the owning layer.

Capture the smallest useful evidence bundle for each failure: one screenshot, the route and viewport, the input that triggered it, the expected result and the first state where it diverged. Add DOM or computed-style evidence only when it explains ownership. A screenshot of a clipped toast says what happened; its bounding box and containing block often say whether the fix belongs in translation, component sizing or positioning.

Retest the complete journey after the local fix. Changing a dialog to logical positioning may repair its entry edge but expose a focus-return or overflow problem on close. Readiness is a property of the interaction sequence, not a collection of isolated screenshots.

Decide readiness by blocker, not by bug count#

A site is not ready if a critical journey cannot complete, the locale is lost, a price or identifier changes meaning, a required control is unreachable, or keyboard users cannot operate the task.

Use a simple decision table:

ResultExampleDecision
Not readyWrong root direction, corrupt value, broken checkout, critical overflowBlock release
High riskWrong currency or date meaning, untranslated critical error, severe focus issueFix or obtain explicit risk acceptance
Follow-upSecondary visual inconsistency with no effect on meaning or operationShip only with owner and retest date
ExpectedIntentional brand name, physical icon that should not mirrorDocument, do not "fix"

Do not reduce readiness to a count of passing pages. One corrupted account number matters more than several minor spacing issues. The question is whether supported users can complete the promised tasks with correct information.

A defensible sign-off names the supported routes, browsers, viewports, locales and test data. It also names what was not covered. "Arabic checkout passed" is weak evidence if it means one desktop screenshot. "Guest and signed-in checkout passed in the supported browser matrix at minimum and wide widths, using Arabic and Latin names, a digit-leading reference, a local phone, invalid payment, server failure and confirmation states" is useful release evidence.

Sample across component families rather than choosing only the most polished pages. Include at least one dense data view, one form-heavy flow, one overlay, one horizontal scroller and one page with user-generated content if the product has them. Testing one instance of each shared component reduces duplicate work, but one passing instance does not prove every configuration. Props, translated strings and container constraints can activate a different code path.

Automate stable evidence such as root attributes, known field direction, formatter options, critical translated labels, focus sequence and unexpected document overflow. Keep human review for language quality, icon meaning, market suitability and whether the complete mixed-direction line is readable.

Most of these tests cite Ritla checks, so a free scan of the critical route answers much of the automated half of this page in one pass. Use its findings to choose the product states that still need hands-on work: the name-and-count test, the keyboard pass, scrolling and the forced failure states.

When the answer is "not yet", how to test an Arabic website before launch turns these tests into a release plan, and the RTL testing checklist is the sweep to repeat on release day.

Checks in this guide

Show every check in this guideShow fewer

See what your Arabic pages are hiding

Paste a URL. Ritla renders the page on desktop and mobile, runs every check, and shows the top issues with screenshot evidence.