A mixed-language message can be perfectly valid text and still use the wrong paragraph direction for its author’s intent:
React یک کتابخانه جاوااسکریپت بسیار محبوب است.
The intended paragraph is Persian, but its first strong character is Latin. This matters in AI answers, documentation and chat bubbles. It is not a reason to reverse the string or change the direction of the whole interface.
Disclosure: I maintain BidiLens, an MIT-licensed mixed-direction text toolkit. This article was prepared with AI assistance and includes a dependency-free solution: use that when it fits.
Try the difference before installing anything
Open the live playground. Choose Persian-majority, English first, then scroll to Live four-way comparison.
The same source appears using browser default direction, explicit RTL, native dir="auto", and BidiLens’s content-majority policy. For this one paragraph, explicit RTL is also a valid solution. The comparison does not prove a library is necessary.
Next choose English-majority with Persian. A blanket RTL rule is not a suitable replacement for choosing direction at each content boundary. Try your own short or balanced sentences too: these are where a heuristic and author intent can disagree.
What dir="auto" actually does
Native dir="auto" uses first-strong direction for the relevant element, with exclusions such as isolated descendants. It does not vote on the majority language. Appending Persian after an existing unisolated Hello does not make it switch merely because Persian now dominates.
That is expected browser behavior, not a broken Unicode algorithm. Content-majority is a different application policy, not a universal correction to the standard.
For known content, express the intent directly:
<p lang="fa" dir="rtl" style="text-align: left">
<bdi dir="ltr">React</bdi> یک کتابخانه جاوااسکریپت بسیار محبوب است.
</p>
Three independent choices are involved: the paragraph reads RTL, the Latin token is isolated LTR, and the paragraph is physically left-aligned. Direction is not alignment. The underlying text stays in logical order.
Where a toolkit helps
Hand-authoring directions is straightforward for a fixed label. It becomes repetitive for unknown user prose, multiple Markdown blocks, and streamed AI output.
BidiLens provides reusable direction policies, inline-isolation planning, streaming state and renderer adapters. The browser still performs bidirectional rendering. Ambiguous input still needs an explicit override or a product-specific policy.
For plain text in an existing React 18/19 app:
npm install @bidilens/react
'use client';
import { BidiMessage } from '@bidilens/react';
export function Message({ text }: { text: string }) {
return (
<BidiMessage
text={text}
inheritedDirection="ltr"
style={{ textAlign: 'left' }}
/>
);
}
This assumes an LTR host. Pass the actual inherited direction in an RTL host. The example deliberately allows Persian to remain physically left-aligned.
This is a plain-text component, not a Markdown renderer. If you already have Markdown plugins, citations, sanitization and code-copy controls, keep that pipeline and use its documented adapter. Do not flatten everything into a string component or attach an external observer to framework-owned DOM.
For ordinary LTR text in an LTR host, without RTL strong characters or bidi formatting controls, the default intervention policy avoids direction/isolation markup. This does not mean zero computation or a guarantee against every host regression.
Start with one message and a rollback
A useful first integration is one read-only message surface behind your existing rollout mechanism. Check:
- Persian beginning with a Latin identifier, and English containing Persian.
- Punctuation, URLs, code, multiline paragraphs and narrow wrapping.
- Explicit direction overrides and left alignment in both host directions.
- The final streamed result and logical copied text against the original source.
- Your real selection, accessibility and editor/IME requirements.
Keep raw prompts, database text and tool arguments unchanged. Rollback should be returning to the previous renderer. Do not install multiple adapters on the same boundary.
The playground’s copy check distinguishes logical selection from clipboard readback. In my latest browser check, selection matched the original text, but clipboard readback was unavailable; that is not evidence of successful system clipboard testing.
BidiLens does not automatically solve terminal shaping or arbitrary editor integration. Native package availability varies. Read the integration guide and limitations before selecting an adapter.
A scoped contribution, not a universal promise
Our mixed-direction message example in PersianLabs UI was merged using native HTML and existing components, with no new BidiLens dependency. That is a scoped contribution, not package adoption.
The practical approach is: identify the text boundary, choose the smallest appropriate policy, preserve the source, and test the actual host.
If you experiment with BidiLens, a reproducible difficult sentence and the renderer/version you used are particularly useful feedback. Please remove private information before sharing examples.
Top comments (0)