Bengal automatically setsdir="rtl" on the <html>element for right-to-left locales (Arabic, Hebrew, Persian, Urdu, etc.). This enables correct text direction and layout mirroring.
Automatic RTL Detection
These locales getdir="rtl"by default:
- Arabic (
ar) - Hebrew (
he) - Persian (
fa) - Urdu (
ur) - Yiddish (
yi) - Divehi (
dv) - Kurdish (
ku) - Pashto (
ps) - Sindhi (
sd)
Config Override
Override inbengal.tomlfor custom or lesser-known RTL locales:
[i18n]
languages = [
{ code = "en", name = "English" },
{ code = "ar", name = "العربية", rtl = true },
{ code = "custom-rtl", name = "Custom", rtl = true },
]
Set rtl = falseto force LTR for a normally RTL locale.
Template Variable
Thedirection() function returns "rtl" or "ltr"for the current page:
<html lang="{{ current_lang() }}" dir="{{ direction() }}">
The default theme uses this automatically.
Default Theme RTL Support
The default theme is fully RTL-ready out of the box:
- CSS logical properties — All directional styles use
margin-inline-start,padding-inline-end,text-align: start, etc. instead of physicalleft/rightproperties. Layout mirrors automatically withdir="rtl". - Bidirectional text isolation — Navigation titles in the docs sidebar, breadcrumbs, prev/next links, and menus are wrapped in
<bdi>tags to prevent mixed-direction text from corrupting visual order. - Breadcrumb separator — Flips from
›to‹in RTL contexts. - Navigation arrows — Prev/next arrows flip direction via
scaleX(-1)in RTL.
No custom CSS is needed for RTL when using the default theme.
CSS Authoring Guidelines
If you're building a custom theme or overriding styles, follow these conventions.
Use Logical Properties
Prefer logical properties so layout flips automatically withdir:
| Physical | Logical |
|---|---|
margin-left |
margin-inline-start |
margin-right |
margin-inline-end |
padding-left |
padding-inline-start |
padding-right |
padding-inline-end |
left |
inset-inline-start |
right |
inset-inline-end |
text-align: left |
text-align: start |
text-align: right |
text-align: end |
border-left |
border-inline-start |
border-right |
border-inline-end |
float: left |
float: inline-start |
float: right |
float: inline-end |
RTL-Specific Overrides
When logical properties aren't enough, use[dir="rtl"]selectors:
/* Flip navigation arrows in RTL */
[dir="rtl"] .nav-arrow {
display: inline-block;
transform: scaleX(-1);
}
/* Change breadcrumb separator in RTL */
[dir="rtl"] .breadcrumbs li:not(:last-child)::after {
content: '‹'; /* Mirrors › */
}
Bidirectional Text Isolation
For mixed LTR/RTL content (e.g. English product names in Arabic navigation), wrap in<bdi>:
{# In navigation templates #}
<a href="{{ item.href }}"><bdi>{{ item.title }}</bdi></a>
{# In body content #}
<p>المنتج <bdi>SuperWidget</bdi> متاح الآن.</p>
<bdi> isolates the embedded text so it renders in its natural direction without affecting surrounding text. The default theme already wraps navigation titles in <bdi>— add it to any custom templates that display user-authored titles in navigation contexts.
Testing RTL
- Add Arabic or Hebrew to your
languagesconfig - Create
content/ar/(orcontent/he/) with translated content - Build and open
/ar/(or/he/) - Verify in the page source:
<html lang="ar" dir="rtl">is present- Layout mirrors correctly (sidebar on right, text right-aligned)
- Navigation arrows point in the correct direction
- Breadcrumb separators use
‹instead of›
- Check mixed-direction content: English words in Arabic paragraphs should display correctly