Nested LTR content inside an RTL page
Embed code, English quotations, URLs, identifiers and third-party widgets inside an Arabic page without forcing the surrounding interface to LTR.
Guide15 min read
An Arabic page is not made entirely of Arabic text. It may contain a stack trace, an email address, an API endpoint, an English incident note or a dashboard embedded from another system. Those values need an LTR base direction without turning their Arabic labels, actions and navigation LTR too.
The implementation rule is simple: change direction at the smallest boundary that owns the LTR content. An entire card is too broad when only its code block is LTR. A plain span is too weak when an inline identifier needs isolation from Arabic punctuation.
Treat direction as content structure. Use CSS for layout around that structure.
Start with the Arabic document#
The document stays Arabic and RTL:
<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8">
<title>مراقبة الأنظمة</title>
</head>
<body>...</body>
</html>Do not switch the root to LTR because one route contains technical content. The root direction should represent the document's predominant content. Nested exceptions get nested boundaries.
W3C's structural direction guidance recommends setting document direction on <html> and changing it on lower structural elements only when their content needs a different base direction.
The page language also remains Arabic. Add lang="en" to an English quotation or prose block, but do not label source code as English just because its keywords use Latin characters. Language and direction are separate metadata.
Choose the smallest complete LTR boundary#
A useful boundary contains all of one LTR unit and none of the surrounding Arabic sentence.
Problem
<section class="incident-card" dir="ltr">
<h2>تفاصيل الحادث</h2>
<p>المسار المتأثر: <code>/v3/events/check</code></p>
<button>إغلاق</button>
</section>The broad LTR boundary affects the Arabic heading, label, action, component alignment and inline ordering.
Better
<section class="incident-card">
<h2>تفاصيل الحادث</h2>
<p>
المسار المتأثر:
<code dir="ltr">/v3/events/check</code>
</p>
<button>إغلاق</button>
</section>Only the API path gets an LTR base direction. The rest of the card inherits RTL from the document. The LTR version of the page keeps the same component structure and geometry.
R020 reports a forced-LTR container, or a bidi override, over Arabic content. When that finding appears, narrow the direction boundary rather than removing every legitimate LTR value.
Use dir="ltr" for known LTR blocks#
Code samples, stack traces, terminal output and fixed English prose have a known base direction. Declare it in markup.
<section class="diagnostic-output">
<h2>سجل الخطأ</h2>
<pre dir="ltr"><code>GET /v3/events/check
504 Gateway Timeout
trace: TRACE-K6-824</code></pre>
</section>The <pre> boundary covers the complete output. The Arabic section heading stays outside it.
For an English quotation, declare both language and direction:
<blockquote lang="en" dir="ltr">
The connection closed before the upstream service returned a response.
</blockquote>The language tag helps pronunciation and language-aware processing. The direction controls bidi layout and punctuation.
Do not use dir="auto" when the direction is already known. An English incident note that begins with an Arabic service name can fool first-strong detection. Explicit LTR is the stable contract.
Isolate known inline values#
Inline technical values need a local base direction and isolation from the Arabic run around them.
<p>
معرّف التتبع
<bdi dir="ltr">TRACE-K6-824</bdi>
</p><bdi> marks the value as a bidirectional isolate. Its internal LTR sequence cannot merge into the surrounding Arabic sentence.
An existing semantic element can carry dir="ltr" too:
<p>
راجع الملف
<code dir="ltr">services/alerts/config.ts</code>
</p>The W3C guide to inline bidi markup recommends tightly wrapping an opposite-direction phrase and declaring its direction. “Tightly” means the element includes the entire LTR value, including punctuation that belongs to it, and excludes Arabic punctuation belonging to the sentence.
R021 reports unisolated bidi hazards such as phones, emails and Latin tokens inside Arabic text.
A plain span does not isolate#
Developers often add a span for styling and assume it creates a text-direction boundary.
<p>
رقم الحادث <span class="incident-id">8642-517-09</span>
</p>It does not. In Chromium 151, measured on 2026-09-24, that three-group Western-digit identifier displays as 09-517-8642 after Arabic text. The source and copied string can still be 8642-517-09, so a DOM snapshot does not expose the visual defect.
Give the fixed-order identifier an explicit isolated boundary:
<p>
رقم الحادث <bdi dir="ltr">8642-517-09</bdi>
</p>Do not call every reversed-looking number wrong. A numeric range can reorder while remaining correct for Arabic reading order. An identifier has fixed groups, so reordering corrupts it. The bidirectional text guide explains that semantic distinction.
Test the value next to its real Arabic label, not alone in a component story. A bare value on its own line can display differently because it lacks the preceding Arabic context that triggers the problem.
Prefer HTML direction metadata to a CSS-only patch#
CSS can control direction, but content direction is usually better expressed with the HTML dir attribute. The attribute remains attached to the value when styles fail to load, and it states the content contract where developers, tests and browser tools can see it.
Problem
<p class="deployment-row">
آخر إصدار: <span class="deployment-ref">release/Q7-hotfix</span>
</p>.deployment-ref {
direction: ltr;
}This gives the span an LTR base direction, but it does not isolate the run from adjacent bidi content. It also hides the reason for the rule in a stylesheet that may be reused beyond this value.
Better
<p class="deployment-row">
آخر إصدار: <bdi dir="ltr">release/Q7-hotfix</bdi>
</p>The element now declares both decisions: the value is LTR, and its ordering is isolated from the Arabic paragraph. CSS can still style its typography, wrapping and selection state.
When markup cannot be changed, CSS isolation is a useful fallback:
.deployment-ref {
direction: ltr;
unicode-bidi: isolate;
}Use isolate, not bidi-override. Isolation contains the directional interaction; an override replaces normal bidi ordering inside the value. Add a comment explaining which content contract requires the fallback, and include the rendered case in a test.
Do not add text-align: left as a substitute for direction. Alignment moves the line box but does not assign the text a base direction or isolate it from neighboring Arabic text. Likewise, direction: ltr does not necessarily mean the box should sit on the physical left. Text order, alignment and component placement are separate decisions.
Keep punctuation inside the phrase it belongs to#
Punctuation is neutral and takes direction from context. A final period or exclamation mark can move to the wrong visual end when it sits outside an opposite-direction boundary.
Problem
<p dir="rtl">
كانت الرسالة <span lang="en">Request timed out</span>.
</p>If the period belongs to the English message, placing it outside the span makes it part of the surrounding Arabic sentence.
Better
<p dir="rtl">
كانت الرسالة <span lang="en" dir="ltr">Request timed out.</span>
</p>Now the complete English phrase, including its punctuation, has one LTR boundary. R024 reports punctuation rendering at the wrong visual end of Arabic text.
The same rule applies to parentheses, trailing colons and symbols that are logically part of a URL or code. Decide ownership before moving punctuation into a wrapper.
Use dir="auto" only when direction is unknown#
User names, comments and imported titles can arrive in either direction. If the value has an existing wrapper, use dir="auto":
<span class="external-title" dir="auto">...</span>If it has no semantic wrapper, use <bdi>, which defaults to automatic direction:
<p>
أضاف <bdi class="external-author">...</bdi> ملاحظة جديدة
</p>MDN's <bdi> reference documents its isolation behavior and automatic direction default.
Automatic direction uses the first strong character. It is a heuristic, so an Arabic comment beginning with a Latin product name can resolve LTR. Prefer stored direction metadata when the content producer supplies it.
Do not put dir="auto" on the whole card if a fixed Latin label appears before the unknown value. The label can decide the card direction before the browser reaches the user content.
Code blocks need LTR text, not an LTR feature shell#
An observability page may include a code viewer with Arabic controls around it. Separate the tool chrome from the code surface.
<section class="code-viewer">
<header class="code-viewer__header">
<h2>الطلب الخام</h2>
<button type="button">نسخ</button>
</header>
<pre class="code-viewer__content" dir="ltr"><code>{
"status": "failed",
"retryAfter": 45
}</code></pre>
</section>The Arabic header follows the page direction. The serialized data stays LTR. Keyboard focus follows DOM order rather than a flipped code-viewer wrapper.
Keep line numbers, selection, horizontal scrolling and syntax tooltips inside the LTR surface when they belong to the code editor. Keep Arabic status labels and page actions outside it.
For a third-party editor, use its documented direction or text model API. A surrounding dir="ltr" may not control a canvas renderer or an editor that owns its internal DOM.
URLs, emails and phones are typed LTR values#
These values should keep their authored order inside Arabic labels, cards and form controls.
<dl>
<div>
<dt>البريد</dt>
<dd><bdi dir="ltr">alerts@north.example</bdi></dd>
</div>
<div>
<dt>الرابط</dt>
<dd><bdi dir="ltr">https://status.example/incidents</bdi></dd>
</div>
</dl>For interactive links, put direction on the value-owning element:
<a href="mailto:alerts@north.example" dir="ltr">
alerts@north.example
</a>Phone input and display have additional punctuation, country-code and editing concerns. Use the phone numbers in RTL interfaces guide rather than treating a phone as ordinary Arabic text.
Do not force the definition list or contact card to LTR. The Arabic terms should remain RTL; only their values need LTR boundaries.
Let long LTR values wrap or scroll within their own box#
URLs, file paths and stack traces are often wider than a mobile Arabic layout. Direction alone does not provide an overflow policy. Choose wrapping or horizontal scrolling according to the value's job.
A prose link can wrap:
.reference-link {
overflow-wrap: anywhere;
}<p>
رابط المرجع:
<a class="reference-link" dir="ltr"
href="https://docs.example/platform/events/retention-policy">
https://docs.example/platform/events/retention-policy
</a>
</p>The link remains one logical LTR value even when the browser wraps it over several visual lines. Check the line starts and punctuation at the wrap points; a narrow screenshot catches failures that a desktop fixture misses.
Code and raw logs usually need preservation rather than arbitrary wrapping:
.raw-event {
max-inline-size: 100%;
overflow-x: auto;
white-space: pre;
}<pre class="raw-event" dir="ltr"><code>upstream=/clusters/primary/events/collector</code></pre>The scroll container belongs to the LTR code surface, not the Arabic card. Test that the beginning and end of the line are reachable with a mouse, touch, Shift+wheel and keyboard where supported. Also verify that using the scroller does not widen the page or create a second page-level horizontal scrollbar.
Truncation needs more caution. An ellipsis can hide the distinguishing end of a path, host or identifier, and mixed direction can make the visible fragment misleading. If space is constrained, provide the complete value through expansion, a details view or a copy action whose accessible name identifies what it copies. Do not rely on a title tooltip as the only route to the full value because it is difficult to use on touch and is not a dependable interaction for every keyboard or assistive-technology user.
When a value must retain exact characters for copying, do not insert visible line-break characters into the stored value. Let CSS wrap the rendering while the DOM text and clipboard payload remain canonical. Verify this by copying the rendered value into a plain-text field and comparing it with the source value.
Set input direction from the value type#
An RTL form still contains inherently LTR fields.
<label for="incident-note">ملاحظة</label>
<textarea id="incident-note" name="note"></textarea>
<label for="callback-url">رابط الاستدعاء</label>
<input
id="callback-url"
name="callbackUrl"
type="url"
dir="ltr"
autocomplete="url"
>
<label for="trace-code">معرّف التتبع</label>
<input id="trace-code" name="traceCode" dir="ltr">The note inherits RTL because Arabic prose is expected. The URL and trace fields are LTR by contract.
R070 reports tel, email or url inputs rendered RTL. R023 reports text inputs rendered LTR where Arabic input is expected.
Test typing, caret movement, selection, deletion around punctuation, pasting and validation. A correct final DOM value does not prove the editing experience.
Avoid putting dir="ltr" on the entire form to fix three technical fields. That would force Arabic labels, help and errors into LTR too.
Decide table direction separately from cell direction#
dir on a table affects column flow as well as text direction. Do not set the whole table LTR just because one column contains identifiers.
For an Arabic incident list, keep table structure RTL and isolate technical cells:
<table>
<thead>
<tr>
<th>الحالة</th>
<th>معرّف التتبع</th>
<th>الخدمة</th>
</tr>
</thead>
<tbody>
<tr>
<td>مفتوح</td>
<td><bdi dir="ltr">TRACE-K6-824</bdi></td>
<td><bdi dir="ltr">alerts-api</bdi></td>
</tr>
</tbody>
</table>If the entire dataset has a defined LTR column order, an LTR table may be valid. Wrap or label Arabic cells locally, and test header-to-cell relationships. The decision should come from the data model, not from the presence of one Latin column.
The W3C structural direction guide documents that table direction affects column order. Visual column placement and DOM reading order still need accessibility testing.
English prose needs both language and direction#
An English legal note, vendor response or quoted log explanation should not be treated like a machine token.
<aside class="vendor-response" lang="en" dir="ltr">
<h2>Vendor response</h2>
<p>The retry policy applies only after the connection closes.</p>
</aside>lang="en" lets assistive technology and language-aware tooling handle the text as English. dir="ltr" supplies its base direction. R080 reports intentional foreign-language runs missing a lang attribute.
If the block contains Arabic annotations, nest them with their own metadata rather than forcing the whole vendor response to serve both languages:
<aside lang="en" dir="ltr">
<p>The retry policy applies after disconnection.</p>
<p lang="ar" dir="rtl">ملاحظة الفريق: راجع حد المحاولات.</p>
</aside>Use semantic nesting that reflects authorship and language. Do not use direction as a substitute for translation metadata.
Third-party widgets have their own boundary#
An iframe is a separate document. The parent page's dir="rtl" does not configure the document inside it. The embedded application needs its own language and direction support.
For an iframe widget:
- pass a supported locale or direction option through its documented API;
- configure the embedded document to render its own root attributes;
- test the iframe content in the Arabic host, not only on its standalone demo page;
- confirm postMessage payloads preserve text and direction metadata where relevant;
- keep the host wrapper's layout logical even if the widget canvas remains physically oriented.
A script-injected widget is different. It adds DOM to the current document and may inherit direction, mount a portal or create a shadow root. Inspect the actual rendered tree and the vendor's current RTL API.
Do not put dir="ltr" on the widget wrapper without evidence. A map canvas can remain physical while its Arabic search control and labels should still be RTL.
If a widget does not support Arabic or RTL, record the limitation as a product dependency. A host-page CSS override is fragile when internal markup changes.
Reapply direction at portals, dialogs and virtualized surfaces#
Some components render outside their apparent parent. A menu may mount under body, a tooltip may use a portal, and a data grid may recycle cells into a separate layer. Inheritance then follows the rendered DOM, not the component tree developers see in source code.
Consider an LTR query token that opens an Arabic explanation tooltip. The token should remain LTR, but the tooltip is Arabic content:
<button type="button" dir="ltr" aria-describedby="query-help">
latency:p95
</button>
<div id="query-help" role="tooltip" lang="ar" dir="rtl">
يعرض زمن الاستجابة عند الشريحة الخامسة والتسعين.
</div>If the tooltip is portalled to the document root, its explicit Arabic metadata prevents it from inheriting an accidental LTR wrapper or library default. The same applies to dialogs opened from code viewers: determine direction from the dialog's content, not from the trigger that launched it.
For virtualized lists and tables, put direction on the value template so every recycled instance receives it. A direction rule applied only to the first rendered row can disappear as the library reuses nodes during scrolling.
Hydration can expose another class of defects. If the server renders an unknown value with no direction and the client adds dir="auto" later, users may see it reorder after load. Make the server and client agree on the direction contract. When direction metadata is stored with the content, render it in the initial HTML. When it is not known, render the automatic boundary on both sides.
Test overlays while open, not just their triggers. Inspect where the rendered node actually lives, then verify its language, direction, focus order and placement at both wide and narrow viewports. A portal can be visually correct while its text direction or reading order is still wrong.
LTR direction changes layout inside its subtree#
dir="ltr" affects more than glyph order. Direction-aware flex rows, grid flow, table columns, logical properties and default alignment inside that subtree can change.
This is why a broad direction boundary can move actions and badges unexpectedly. A component using margin-inline-start interprets start from its nearest direction context. Inside an LTR technical panel, start is left even though the surrounding Arabic page starts on the right.
Keep outer Arabic layout and inner LTR content as separate boxes:
.diagnostic-output {
display: grid;
gap: 0.75rem;
}
.diagnostic-output__code {
overflow: auto;
text-align: start;
}<section class="diagnostic-output">
<h2>تفاصيل الاستجابة</h2>
<pre class="diagnostic-output__code" dir="ltr"><code>...</code></pre>
</section>The grid inherits RTL for its Arabic composition. The code block has an LTR text and scroll context. Do not use physical padding or offsets to compensate for the nested direction; use the RTL CSS guide when layout should respond to start and end.
Keep DOM order logical#
Direction can change visual inline flow, but it does not rewrite DOM order. Do not add row-reverse, CSS order or positive tabindex to make an LTR technical block appear in a chosen position.
For a toolbar with Arabic labels around an LTR query editor, keep task order in the DOM. Let logical layout place the groups. Test Tab from the first action through the editor to the final action in both locales.
A broad LTR boundary can make an ordinary flex row begin on the left. If only the editor text should be LTR, put the boundary on the editor surface rather than the toolbar. This keeps toolbar flow aligned with the Arabic task sequence.
R081 reports row-reverse used to fake RTL instead of document direction, where tab order fights visual order.
Screen-reader order follows logical content, not a screenshot. Test focus and spoken sequence whenever nested direction changes interactive composition.
Preserve accessible names and clipboard values#
Direction wrappers should not change what controls are called or what users copy. A copy button needs an Arabic accessible name even when its target value is LTR:
<div class="trace-value">
<code id="trace-value" dir="ltr">TRACE-K6-824</code>
<button type="button" aria-describedby="trace-value">
نسخ معرّف التتبع
</button>
</div>The visible Arabic action remains readable in the page direction. The separate code node owns the LTR value. Product code can copy the exact text from the code node rather than reconstructing it from the visual order.
Avoid putting an entire Arabic label inside an LTR element simply so the label and value form one accessible name. Keep each language and direction run explicit. Where a control needs a mixed-language name, test it with the screen readers and browsers your product supports; pronunciation, pauses and punctuation can differ even when the visual result looks correct.
Copy tests should cover more than the Clipboard API returning without error. Paste into a plain-text target and compare code points with the expected source. This catches injected direction controls, copy code that reconstructs the visual order, and accidental whitespace. If the application deliberately adds an invisible bidi control to exported text, document that contract and test the receiving systems. Invisible controls copied into tickets, terminals or search boxes can be difficult to diagnose.
Selection is also part of the experience. Drag across the Arabic label and its LTR value, then repeat with keyboard selection. Confirm that the highlight may move visually according to bidi rules while the copied text remains logically meaningful. Do not respond to unusual-looking selection by flattening the whole row to LTR.
For status announcements, keep the dynamic Arabic sentence in an RTL live region and isolate only the inserted technical value. Assistive technology receives one coherent update without changing the page shell or the technical token's authored order.
Do not use bidi overrides for ordinary LTR content#
<bdo> and CSS unicode-bidi: bidi-override force character ordering instead of letting the bidirectional algorithm resolve scripts. They are not stronger versions of dir="ltr".
Use ordinary direction and isolation for code, English prose, URLs and identifiers. Reserve overrides for specialized cases where showing characters in a forced order is the actual requirement.
W3C's inline bidi guidance recommends markup boundaries and explains why invisible controls and overrides are harder to manage. Markup is visible in the DOM, can carry language, and can be tested at the exact content boundary.
Search existing styles for:
direction: ltr;
unicode-bidi: bidi-override;If the rule wraps ordinary Arabic and LTR content, replace it with semantic boundaries. A forced override over Arabic content is covered by R020.
Avoid mirroring technical content#
LTR content is not the same as a horizontally mirrored object. Do not apply scaleX(-1) to code, charts, screenshots, maps or embedded widgets just because the surrounding page is RTL.
Direction controls text and flow. Mirroring changes geometry. A source-code line should remain authored left to right; an Arabic “next” chevron may need a directional variant; a geographic map retains physical orientation.
Review each asset by meaning:
- code, log output and terminal captures stay unmirrored;
- graphs keep the axis semantics defined by the product;
- directional controls follow the sequence they advance;
- brand marks stay unchanged;
- screenshots of LTR software remain accurate to their source;
- Arabic annotations around those assets follow the page direction.
The guide to what should be mirrored in RTL separates reading-direction cues from physical or universal symbols.
Test nested direction with product-shaped fixtures#
Create fixtures that place each LTR type in its real Arabic context:
- a digit-leading incident identifier after an Arabic label;
- a Latin trace token inside an Arabic status sentence;
- an English paragraph with final punctuation;
- a multi-line stack trace with long file paths;
- an email, URL and phone value;
- an Arabic note inside an English vendor block;
- an Arabic table with two LTR value columns;
- an embedded widget that opens a menu or dialog;
- a narrow viewport where the LTR block scrolls internally;
- copy, selection and keyboard interaction.
Assert the boundaries and resolved directions:
// page and expect are supplied by the browser test runner.
const shell = page.locator("[data-test=incident-card]");
const output = shell.locator("pre");
await expect(shell).toHaveCSS("direction", "rtl");
await expect(output).toHaveAttribute("dir", "ltr");
await expect(output).toHaveCSS("direction", "ltr");Then inspect visible order, punctuation, wrapping and scroll reachability. Attribute checks prove the intended boundaries; they do not prove that CSS, content or third-party internals respect them.
Test LTR and RTL routes with the same component state. A local dir="ltr" fix should preserve the English version rather than create a second code path.
Debug from the content outward#
When nested LTR content looks wrong:
- Identify the smallest value or block that should be LTR.
- Confirm the Arabic document root still has
lang="ar" dir="rtl". - Inspect the LTR element's own
dirand computeddirection. - Check whether the boundary includes Arabic labels or actions by accident.
- Verify inline values are isolated, not merely wrapped in a span.
- Move punctuation into the phrase that owns it.
- Inspect logical spacing and flex or grid flow inside the LTR subtree.
- Check the real DOM for portals, shadow roots and iframe boundaries.
- Test editing, copy, focus and screen-reader order.
- Re-run at narrow widths with long content.
Do not repair the symptom with a page-wide LTR override. A correct fix should leave the Arabic shell RTL and make the exception explicit in markup.
Keep the exception smaller than the component#
Nested LTR content works when each directional unit owns its boundary: code blocks get dir="ltr", English prose gets language and direction, fixed inline values get isolation, and unknown values use automatic direction. The Arabic interface should not have to surrender its direction to host them.
A Ritla scan can surface forced-LTR Arabic containers and unisolated mixed values after these components render. Use the bidirectional text guide for complex inline ordering, and the phone-number guide for the editing and formatting rules specific to telephone values.
Checks in this guide
- R020Forced-LTR container, or a bidi override, over Arabic content
- R021Unisolated bidi hazards: phones, emails, Latin tokens inside Arabic text
- R024Punctuation rendering at the wrong visual end of Arabic text
- R070tel/email/url inputs rendered RTL (these must stay LTR)
- R023Text inputs rendered LTR where Arabic input is expected
- R080Intentional foreign-language runs missing a lang attribute