If you’ve ever worked with Arabic, Persian, Hebrew, Urdu, or any RTL (Right-to-Left) language on the web, you probably know the pain.
Mixed RTL/LTR text rendering breaks unexpectedly. Punctuation looks wrong. Numbers don’t match the locale. Ellipsis appears on the wrong side. URLs inside Arabic text become unreadable. And emails or plain-text environments completely destroy formatting.
After dealing with this problem repeatedly, I decided to build:
rtl-text-tools
A lightweight RTL text processing toolkit for JavaScript and TypeScript.
It handles:
- RTL detection
- Direction normalization
- Arabic/Persian digit conversion
- RTL punctuation conversion
- Ellipsis fixing
- Unicode bidi wrapping
- CSS helpers
- DOM helpers
And it works all the way back to IE11 with zero runtime dependencies.
Why This Exists

Most internationalization libraries focus on translations and formatting APIs.
But very few actually solve the rendering problems of RTL text itself.
For example:
"مرحبا, رقم 123..."
Visually, this often renders awkwardly in mixed-direction environments.
You usually want:
"...مرحبا، رقم ۱۲۳"
That means:
- move ellipsis to the correct visual side
- convert punctuation
- convert digits
- preserve RTL readability
That’s exactly what rtl-text-tools does.
Installation
npm install rtl-text-tools
Quick Example
import { fixRTL } from 'rtl-text-tools';
fixRTL('مرحبا, رقم 123...');
// → "...مرحبا، رقم ۱۲۳"
Arabic digits are also supported:
fixRTL('مرحبا, رقم 123...', { lang: 'arabic' });
// → "...مرحبا، رقم ١٢٣"
If the text isn’t RTL, it returns the original string unchanged:
fixRTL('Hello world');
// → "Hello world"
Features
1. RTL Detection
Detect whether text contains RTL scripts.
import { hasRTL } from 'rtl-text-tools';
hasRTL('مرحبا'); // true
hasRTL('שלום'); // true
hasRTL('Hello'); // false
Supports:
- Arabic
- Hebrew
- Persian/Farsi
- Urdu
- Syriac
- Thaana
- N’Ko
- Samaritan
- Mandaic
- and more
2. Digit Conversion
Convert Latin digits into locale-specific numerals.
Persian digits
import { toPersianDigits } from 'rtl-text-tools';
toPersianDigits('Price 123');
// "Price ۱۲۳"
Arabic-Indic digits
import { toArabicDigits } from 'rtl-text-tools';
toArabicDigits('Price 123');
// "Price ١٢٣"
3. RTL Punctuation Conversion
Convert standard punctuation into RTL equivalents.
import { convertPunctuation } from 'rtl-text-tools';
convertPunctuation('مرحبا, كيف حالك?');
// "مرحبا، كيف حالك؟"
Converts:
LTRRTL,،?؟;؛
4. Ellipsis Fixing
One of the most annoying RTL rendering issues.
import { moveEllipsis } from 'rtl-text-tools';
moveEllipsis('مرحبا...');
// "...مرحبا"
Also supports the Unicode ellipsis character:
moveEllipsis('مرحبا…');
// "…مرحبا"
5. Bidi Wrapping for Plain Text
CSS doesn’t exist in:
- emails
- terminals
- textareas
- logs
- PDFs
- some chat systems
For those environments, Unicode bidi markers are essential.
import { wrapRTL } from 'rtl-text-tools';
wrapRTL('مرحبا');
It wraps text using invisible Unicode direction control characters for reliable RTL rendering.
You can also safely embed LTR content inside RTL paragraphs:
import { wrapLTR } from 'rtl-text-tools';
wrapLTR('https://example.com');
6. React + CSS Helpers
import { getRTLStyles } from 'rtl-text-tools';
<div style={getRTLStyles()}>
مرحبا بالعالم
</div>
Returns:
{
direction: 'rtl',
unicodeBidi: 'embed'
}
7. DOM Helper
import { setDirAttribute } from 'rtl-text-tools';
setDirAttribute(element, 'ar');
Outputs:
<div dir="rtl" lang="ar">
IE11 Compatibility

I intentionally made this package compatible with legacy environments.
The compiled output targets ES5:
- no arrow functions
- no replaceAll
- no regex u flag
- no modern syntax assumptions
So yes , it even works in IE11.
The Real Problem With RTL on the Web
Most developers only think about:
direction: rtl;
But RTL support is actually much deeper than that.
The difficult part is:
- mixed-direction content
- Unicode bidi behavior
- punctuation mirroring
- locale digits
- inline URLs
- plain-text rendering
- email clients
- terminals
- copy/paste consistency
This package tries to solve those practical problems in one place.
Example: Mixed RTL/LTR Text
Without normalization:
من در پارکی راه می رفتم Do not Park here
The rendering can become visually confusing depending on the environment.
With normalization:
normalizeDirection(text)
The text becomes readable with proper RTL base direction.
Why Zero Dependencies?
Text utilities should be lightweight.
This package is:
- dependency-free
- tree-shakeable
- framework-agnostic
- TypeScript-friendly
- browser-compatible
- usable in Node.js
Open Source
The project is fully open source and contributions are welcome.
GitHub: https://github.com/homayounmmdy/rtl-text-tools
NPM: https://www.npmjs.com/package/rtl-text-tools
Final Thoughts
RTL support on the web is still surprisingly underdeveloped.
A lot of developers building multilingual products end up reinventing the same utilities repeatedly.
I wanted a small toolkit that handled the annoying RTL edge cases properly and could be dropped into any project easily.
If you work with Arabic, Persian, Hebrew, Urdu, or multilingual interfaces, I hope this package saves you some time.
Feedback, issues, and contributions are always welcome.
Top comments (1)
Such a great tool keep going