<bdi> vs dir="auto": which one to use
Learn when bdi and dir="auto" are equivalent, where their scope differs, and how to choose markup for inserted values, fields and user content.
By Omran Khleifat, Founder of Ritla
Guide13 min read
Replacing <bdi> with <span dir="auto"> does not remove bidi isolation. For an ordinary inserted inline value, both infer direction from the content and isolate it from the surrounding sentence. A comparison that says one isolates while the other only detects direction gives engineers the wrong reason to choose.
The useful distinction is where the direction belongs. Use <bdi> when an inserted inline value needs a wrapper and no more meaningful element fits. Put dir="auto" on an existing link, heading, paragraph or text control when that element owns the content whose direction is unknown. Neither choice replaces an explicit direction when the product already knows it.
Consider a museum collections workspace. Its Arabic interface contains staff-selected collection names, accession identifiers and conservation notes written in either Arabic or English. These are different content contracts. Giving all of them the same wrapper makes the markup consistent at the expense of expressing what each component needs.
The inline case: either choice can fix the same failure#
An accession identifier has a defined group order. An Arabic-speaking curator comparing the workspace with a physical label should see the identifier in that order, even though the surrounding label is read from right to left.
Problem
<p dir="rtl">رقم الاقتناء: <span>864205-3197</span></p>After the Arabic label, the identifier displays as 3197-864205. A plain span supplies no isolation boundary. The result looks like a different identifier, not merely a different alignment of the same paragraph.
These two alternatives repair this reproduction:
<p dir="rtl">رقم الاقتناء: <bdi>864205-3197</bdi></p><p dir="rtl">رقم الاقتناء: <span dir="auto">864205-3197</span></p>Both keep the identifier as 864205-3197. These concrete reorderings follow the measurements supplied for this guide in Chromium 151, last checked on 2026-09-24. Repeat the fixtures in your supported Firefox and Safari versions rather than treating those measurements as evidence for every browser.
The example proves equivalence for this inline use, but automatic direction is not the best description of this particular data contract. If accession identifiers are specified as LTR, write <span dir="ltr">864205-3197</span>. The format has already answered the direction question.
For a collection name entered by a curator, the direction really is unknown. Either <bdi> or <span dir="auto"> is appropriate. The choice between them should not depend on whether today's example contains Arabic. It should reflect the range of values that field accepts.
What is shared, and what is different#
bdi is an HTML element. Its default direction is automatic, and its content is isolated. dir is an HTML attribute with ltr, rtl and auto values. On an ordinary inline element, dir="auto" supplies both automatic direction and isolation. MDN's bdi reference describes the inline alternatives.
| Question | bdi | dir="auto" |
|---|---|---|
| Does it need a new element? | Yes, it is the element | No, it modifies an element |
| Does it infer direction? | By default | Yes, where the attribute applies |
| Can it isolate an inserted inline name? | Yes | Yes, on its inline wrapper |
| Can it preserve an existing heading or link? | By adding a wrapper inside it | By going directly on that element |
| Is it the way to set a text control's own direction? | No | Yes, on the control |
| Is it a container for several paragraphs? | No, its content model is phrasing content | It can go on an appropriate block element |
| Can direction be specified explicitly? | Yes, with dir="ltr" or dir="rtl" | Use those values instead of auto |
Do not read “automatic” as “make every character run in one direction.” Both choices preserve normal bidirectional processing inside the selected boundary. Arabic letters still form RTL runs, Latin letters form LTR runs, and punctuation participates according to its context.
Also distinguish automatic direction from inheritance. A normal span with no dir generally inherits direction. A bdi with no dir uses its automatic default. Removing an apparently redundant attribute during cleanup can therefore change a span without changing a bdi in the same way.
There is no need to write <bdi dir="auto"> for ordinary values. It is valid, but the attribute repeats the default. Keeping it may fit a component convention; it does not add another layer of isolation.
Put automatic direction on the element that owns the content#
Suppose a collection name is already a link. Creating a nested wrapper solely for direction adds structure without adding information the link could not carry itself.
Both versions below are valid. The second expresses the boundary directly on the existing element:
<p dir="rtl"> المجموعة: <a href="/collections/coastal-maps"><bdi>Coastal maps</bdi></a></p><p dir="rtl"> المجموعة: <a href="/collections/coastal-maps" dir="auto">Coastal maps</a></p>The URL is an example route in the museum application. Keep the link's destination and accessible text intact while changing its direction markup. A direction fix should not replace a meaningful element with a generic one.
The same reasoning applies to a collection heading:
<h3 dir="auto">خرائط الساحل</h3>This heading represents a curator-entered title. If it instead said a fixed Arabic interface label such as “Collection details,” its direction would already be known. Automatic direction is useful because the title varies, not because headings inherently need it.
Use <bdi> when there is no existing element that owns only the inserted value:
<p dir="rtl">المجموعة النشطة: <bdi>خرائط الساحل</bdi></p>Here the paragraph owns the Arabic sentence, while the new inline element owns the title. The distinction between a page heading and a value inside a sentence is more useful than a project-wide preference for one spelling.
There is an edge case when an existing link contains more than the title, such as an independently labelled status or counter. Then the link and title do not own the same text. A narrower inner boundary may be appropriate. Inspect the actual children before moving dir to an ancestor. W3C's inline markup guidance explains choosing boundaries for inserted phrases.
Automatic direction only sees the content in its scope#
For simple text, the first strong directional character selects the base direction. Digits and ordinary punctuation do not select it. A value with no strong character resolves to LTR, even inside an RTL parent. This behavior is shared by <bdi> and dir="auto"; switching between them will not change it.
That makes a label inside the boundary consequential.
Problem
<p dir="auto">رقم الاقتناء: 864205-3197</p>The Arabic label selects RTL for the paragraph. Automatic direction on the whole paragraph does not separate the identifier from the label. Changing this to a bdi containing the same combined string would still leave the label and identifier together.
Better
<p dir="rtl">رقم الاقتناء: <span dir="ltr">864205-3197</span></p>The paragraph has a known Arabic direction; the identifier has its own known format. The repaired boundary represents the data model rather than guessing from a combined label-value string.
Automatic direction is also not a count of Arabic versus Latin letters. A conservation note that begins with an English project name and continues in Arabic can select LTR. If the author knows the intended paragraph direction, offer a way to specify it. Replacing span dir="auto" with bdi does not improve that heuristic.
For a detailed explanation of the selection algorithm, see how dir="auto" works. In code review, the immediate question is simpler: which text is allowed to choose direction for this element?
User content blocks need their own direction#
The conservation workspace displays notes entered by staff. The note body can be Arabic or English independently of the interface language.
Problem
<section dir="rtl"> <h2>ملاحظات الترميم</h2> <p>Inspect backing!</p></section>The English note inherits RTL. In this context, its final exclamation mark displays at the left end, as !Inspect backing. That is a text-direction problem, not a reason to move the whole section to the other side of the screen.
Better
<section dir="rtl"> <h2>ملاحظات الترميم</h2> <p dir="auto">Inspect backing!</p></section>The note now supplies its own direction. If the same record instead contains an Arabic note, automatic direction can select RTL without changing the interface heading. For a note known to be English, explicit LTR is also suitable.
<p><bdi>Inspect backing!</bdi></p> can isolate the text inside the paragraph, but it does not declare the paragraph's own direction. That difference matters when the product wants the paragraph, including its start alignment, to follow its content. Put the attribute on the paragraph that represents the note.
For rich text, do not wrap a sequence of paragraphs in bdi. Keep valid document structure and choose whether each paragraph needs independent direction:
<section dir="rtl"> <h2>ملاحظات الترميم</h2> <p dir="auto">Inspect backing!</p> <p dir="auto">يجب فحص الإطار قبل العرض.</p></section>Putting dir="auto" only on a single outer container would choose one base direction from its eligible content; it would not independently choose for each ordinary child paragraph. Apply direction where the editorial unit requires it. W3C's structural direction guidance covers automatic direction for user content blocks.
Keep author metadata out of a note's direction decision#
A subtler failure appears when a note contains both staff metadata and the body. The first visible name may be Latin even when the note is Arabic.
Problem
<p dir="auto"><span>Marta Ruiz</span>: يجب فحص الإطار قبل العرض.</p>The plain span does not exclude the author's name from automatic direction selection. The initial Latin letter selects LTR for the paragraph. The application intended the note body to determine direction, but it allowed metadata to answer first.
A bdi around the name changes that selection boundary:
<p dir="auto"><bdi>Marta Ruiz</bdi>: يجب فحص الإطار قبل العرض.</p>The outer automatic-direction scan skips the nested bdi. It can then find the Arabic body. A nested element with its own valid dir is also excluded, so a span dir="auto" around the name serves the same purpose. This is a scope difference from a plain span, not a hidden advantage of the bdi spelling. The HTML directionality algorithm defines those exclusions.
For a note card, separate metadata and body may be easier to maintain:
<article dir="rtl"> <p>كاتب الملاحظة: <bdi>Marta Ruiz</bdi></p> <p dir="auto">يجب فحص الإطار قبل العرض.</p></article>Now adding a staff badge or changing the header template cannot accidentally make it the first text in the note body. Test this boundary when metadata is optional, when the author is missing, and when the body is empty. The remaining eligible text can differ between those states.
Do not make every descendant automatic as a precaution. Once a child establishes its own direction boundary, it may no longer contribute to an ancestor's automatic selection. Scope should follow the intended content units, not a blanket selector or a universal attribute added to every element.
Form fields: put dir on the control#
An input's editable value is not a child text node that an outer bdi can manage. If a museum search field accepts Arabic or English collection titles, set automatic direction on the field itself.
Problem
<div dir="rtl"> <label for="collection-query">ابحث في المجموعات</label> <bdi><input id="collection-query" type="search"></bdi></div>The wrapper does not tell the control to infer direction from its editable value. Do not treat the presence of a bdi ancestor as evidence that typing Arabic will select RTL in the input.
Better
<div dir="rtl"> <label for="collection-query">ابحث في المجموعات</label> <input id="collection-query" type="search" dir="auto"></div>The control now owns the direction decision. Its label stays in the interface's direction. Test typing, pasting, clearing and replacing the value; do not validate only a prefilled field.
The empty state needs a separate decision. An empty automatic input is LTR. An Arabic placeholder therefore appears at the left edge in the supplied measurements, and the field switches to RTL when Arabic is entered. A placeholder is not a substitute for an actual Arabic value when testing automatic direction.
If a field is specifically for Arabic text and the product expects RTL from the empty state onward, explicit dir="rtl" may better express that requirement. If it accepts either direction, automatic selection can be the intended behavior even though its empty state starts LTR. Decide that requirement before filing the empty state as a defect.
Known-format fields are a different case. An accession reference with an LTR format should use dir="ltr"; accepting user input does not make its direction unknown. Direction policy follows the field's purpose, not whether the value came from a keyboard. MDN's dir reference covers attribute values and inheritance.
Editing and displaying a note are separate decisions#
A conservation-note editor can use the attribute directly:
<label for="conservation-note">ملاحظة الترميم</label><textarea id="conservation-note" dir="auto"></textarea>An automatic textarea has special rendering behavior: paragraph direction can be determined separately for its text paragraphs. Do not assume a single computed direction value fully describes a multiline editor. The HTML bidi rendering rules define the relevant treatment.
Test an Arabic paragraph followed by an English paragraph in the editor. Then save the note and inspect its read-only presentation. A renderer that puts the entire saved value into one ordinary paragraph is not reproducing a structured set of independently directed paragraphs.
This does not require storing presentation markup inside the note. Preserve the application's text or rich-text model, and make its display component express paragraph boundaries and direction deliberately. If the product stores an author's explicit direction choice, use that information rather than discarding it and guessing again.
Test the edit-preview-save cycle as one workflow. Confirm that neither the preview nor the saved note loses the selected direction. A direction fix only in the editor can leave the public or read-only view with the original defect. For textarea-specific attributes and behavior, see MDN's textarea reference.
Do not use CSS or overrides to manufacture a difference#
If replacing span dir="auto" with bdi changes a simple inline fixture unexpectedly, inspect the stylesheet and actual DOM before concluding that the two have different automatic algorithms. A component rule may be targeting one element or overriding its bidi behavior.
direction and unicode-bidi are separate computed properties. The first describes a base direction; the second controls participation in bidi processing. CSS direction: ltr alone on a normal inline span is not the same declaration as an HTML direction boundary. Inspect both properties when a fix appears ineffective.
An override such as unicode-bidi: bidi-override changes character ordering rather than simply separating the inserted value. It can make a particular numeric fixture look right while breaking a human-authored Arabic name. MDN's unicode-bidi documentation distinguishes isolation, embedding and overrides.
Neither automatic option guarantees source-order display for every numeric script and separator combination. In the supplied measurements, spaced Arabic-Indic digit groups still reorder inside an isolate. Keep the Western-digit accession fixture separate from tests of other identifier formats. Fixing a boundary is not permission to promise that every possible string becomes visually unchanged.
Language is another independent property. dir="auto" does not discover a language, and bdi does not label one. Add an appropriate lang when the content's language is known, without assuming that LTR means English. For broader cases, use dynamic text direction.
Make the choice part of the component contract#
A reusable component needs more information than “this string came from the server.” The same API response can contain a known-format identifier, an unknown-direction title and a translated interface label. Their common origin does not give them the same direction policy.
Record the policy for each rendered field:
- An accession reference has explicit LTR direction because its format defines the reading order.
- A collection title defaults to automatic direction because curators can supply either script.
- A conservation-note paragraph defaults to automatic direction unless the author has specified a direction.
- An Arabic interface label follows the interface's known direction.
Then let the rendering context determine the element. The title can use bdi in a sentence, dir="auto" on a heading, and dir="auto" on its editing input. Those are three presentations of one content policy, not three incompatible treatments of the title.
If a component accepts explicit direction metadata, restrict it to supported values. Do not pass arbitrary stored strings through as attribute values, and do not treat an empty attribute as shorthand for automatic selection. Make the fallback deliberate. This small example updates the existing collection-title element after it exists:
<h3 id="collection-title" dir="auto"></h3>const record = { title: "خرائط الساحل", direction: "auto"};const title = document.getElementById("collection-title");const acceptedDirections = new Set(["ltr", "rtl", "auto"]);title.dir = acceptedDirections.has(record.direction) ? record.direction : "auto";title.textContent = record.title;The component retains its heading semantics and inserts the title as text. Bidi markup does not make unsafe HTML insertion safe, and escaping content does not establish a direction boundary. Keep those responsibilities separate in the implementation.
Test the component across record changes. Load an Arabic title, replace it with the Latin title, then load a title with explicit direction metadata. Finally replace that record with one using the automatic default. A stale explicit direction from the previous record should not survive because an update path only changed the text.
Also test fallback rendering. If the title is missing and the component displays an Arabic interface phrase, the fallback is known interface content rather than an unknown curator-entered title. Decide whether it uses a separate branch or the same element, and verify the resulting direction. An empty automatic node and a populated Arabic fallback are different states.
This contract also makes migrations reviewable. When replacing a title's bdi wrapper with dir="auto" on a link, preserve the same owned text, punctuation and update paths. When moving direction to a larger ancestor, treat that as a change of scope requiring new fixtures. A tag substitution and a boundary expansion are different changes, even if a single screenshot looks identical.
Verify equivalence and scope in the browser#
Keep the two inline implementations beside each other in a small test page. Give them the same class, value and surrounding sentence. Otherwise a comparison can accidentally test different CSS or different punctuation rather than the choice of markup.
Use this fixture set in the museum workspace:
| Fixture | What the comparison should establish |
|---|---|
Accession 864205-3197 after its Arabic label | Both isolated inline forms preserve its defined group order |
Arabic collection title خرائط الساحل | Either inline form selects RTL from the value |
Latin collection title Coastal maps | Either inline form selects LTR from the value |
English note Inspect backing! | Direction on the paragraph keeps punctuation with its intended sentence |
| Latin staff name before an Arabic note | Metadata does not choose direction for the note body |
| Empty and then Arabic search input | Automatic direction belongs to the control and follows its current value |
| Arabic and English paragraphs in a saved note | Display scope matches the content's paragraph structure |
With the value element selected in DevTools, inspect both markup and computed properties:
const element = $0; // Select the value or control in DevTools first.const style = getComputedStyle(element);({ tag: element.localName, declaredDirection: element.getAttribute("dir"), computedDirection: style.direction, bidiMode: style.unicodeBidi});For the automatic input, inspect the control itself, then type a new value and repeat. Inspecting only its wrapper answers the wrong question. For a note, inspect which descendant text can participate in the outer direction selection.
After the initial comparison, change values dynamically, test narrow widths and repeat on the English route. Keep a visual assertion alongside DOM assertions. Copying text preserves its logical order even when the displayed groups move, so a successful copy test cannot establish a correct visual result.
In code review, accept either inline spelling when its boundary is correct. Request a change when automatic direction is on the wrong ancestor, a known-format value has no explicit policy, or a field's wrapper is being mistaken for the field itself.
A free Ritla scan can report , unisolated bidi hazards: phones, emails, Latin tokens inside Arabic text. Use the component fixtures to verify the boundary you chose, then read how dir="auto" works for selection details or nested LTR content inside an RTL page when a whole region needs a known direction.