You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
apps/desktop is an Electron app rendering apps/web (React 19 + Tailwind v4), so the renderer is just Chromium and already knows how to lay out bidirectional text correctly. What's blocking RTL today is two things in the web codebase:
The current Tailwind usage is dominantly physical, not logical. A quick scan of apps/web/src shows utilities like text-left, ml-auto, -ml-0.5, pl-[90px], pl-2, pr-1.5, etc. used throughout components such as Sidebar.tsx and contextMenuFallback.ts. These never mirror, regardless of the document direction.
There is no bidi handling in message content. I couldn't find any uses of unicode-bidi, plaintext, or isolate anywhere in apps/web/src. That means when an assistant message contains Arabic (or any RTL text), Chromium falls back to the default LTR base direction and inline LTR tokens — code spans, mentions like @user, tool tags like pint, file paths — get visually shuffled inside the Arabic sentence. This is exactly the bug visible when using t3code on Arabic projects today.
Retrofitting RTL later is painful: every spacing, alignment, border, and positioning utility has to be revisited. It's much cheaper to standardize on logical utilities now, while the surface area is still small, so the renderer is bidi-ready by construction instead of needing a migration sprint later.
Proposed solution
Adopt logical Tailwind utilities + browser-native bidi handling as the convention in apps/web:
Prefer logical Tailwind utilities over physical ones in components:
Tailwind v4 supports all of these out of the box, and in an LTR context they render identically to the physical versions, so the diff is behavior-preserving.
Let the browser handle bidi text inside message bodies:
Set dir=\"auto\" on assistant/user message content containers so Chromium picks the base direction from the first strong character per element. No JS detection needed.
Apply unicode-bidi: plaintext to message paragraphs (e.g. via a small utility class or directly on the markdown renderer's wrapper) so each line resolves independently. This is what fixes inline pint / @user / URLs getting shuffled inside Arabic sentences.
Pin code blocks, diffs, and file paths to LTR with dir=\"ltr\" + unicode-bidi: isolate, so source code stays LTR even when embedded inside an RTL message.
Keep the app chrome LTR by default. No global "RTL mode" toggle. Only message bodies that actually contain RTL content flip themselves, which matches how GitHub and VS Code handle it and avoids a disruptive feature.
(Optional, but cheap) Add a lint rule that flags physical Tailwind utilities in component class lists, so the convention doesn't drift back. There's prior art in the Tailwind community for this via custom ESLint rules / eslint-plugin-tailwindcss.
Why this matters
Cheap now, expensive later. Logical utilities are a drop-in replacement with identical behavior in LTR contexts, so adopting them today costs almost nothing. Doing it after the UI has grown means touching every component.
Unblocks Arabic / Hebrew / Persian / Urdu users for free. Once message containers use dir=\"auto\" and the chrome uses logical utilities, the renderer just works for RTL content without a dedicated feature.
Fixes a real bug visible today, where Arabic assistant output renders with inline code tokens floating to the wrong side of words.
Aligns with the platform. Chromium, the CSS Logical Properties spec, and Tailwind v4 itself all encourage this — it's the conventional way to write Tailwind in 2026.
Smallest useful scope
A first PR that:
Wraps the message content container (the markdown renderer's outer element) with dir=\"auto\" and applies unicode-bidi: plaintext to its paragraphs.
Wraps code blocks / inline code in dir=\"ltr\"; unicode-bidi: isolate.
Migrates a single high-traffic component (e.g. Sidebar.tsx or the chat message component) from physical to logical Tailwind utilities as a reference for the rest of the codebase.
That alone makes Arabic conversations readable. The remaining components can be migrated incrementally, and a lint rule can be turned on once the codebase is clean.
Alternatives considered
Retrofit RTL support later as a feature. Strictly worse: more code to touch, more regressions, and users are blocked in the meantime.
Global "RTL mode" toggle that flips the whole app. Breaks mixed-language workflows (most users want LTR chrome with correctly-rendered RTL message bodies) and doesn't fix inline bidi issues on its own.
Manual per-message direction detection in JS. Reinvents what the browser already does correctly via dir=\"auto\" and unicode-bidi.
Risks or tradeoffs
A small number of cases (drag handles, animations, transforms) may still need physical values; those can stay physical and be called out explicitly.
Need to make sure code blocks, diffs, tables, and file paths stay LTR even when nested inside an RTL message — handled by step 3.
The migration touches a lot of files mechanically, but the diff is mostly find-and-replace and behavior in LTR is identical, so review risk is low.
This discussion was converted from issue #1771 on August 15, 2026 09:40.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Before submitting
Area
apps/webrenderer styling (Tailwind v4 utility usage + bidi handling in message bodies).Problem or use case
apps/desktopis an Electron app renderingapps/web(React 19 + Tailwind v4), so the renderer is just Chromium and already knows how to lay out bidirectional text correctly. What's blocking RTL today is two things in the web codebase:apps/web/srcshows utilities liketext-left,ml-auto,-ml-0.5,pl-[90px],pl-2,pr-1.5, etc. used throughout components such asSidebar.tsxandcontextMenuFallback.ts. These never mirror, regardless of the document direction.unicode-bidi,plaintext, orisolateanywhere inapps/web/src. That means when an assistant message contains Arabic (or any RTL text), Chromium falls back to the default LTR base direction and inline LTR tokens — code spans, mentions like@user, tool tags likepint, file paths — get visually shuffled inside the Arabic sentence. This is exactly the bug visible when using t3code on Arabic projects today.Retrofitting RTL later is painful: every spacing, alignment, border, and positioning utility has to be revisited. It's much cheaper to standardize on logical utilities now, while the surface area is still small, so the renderer is bidi-ready by construction instead of needing a migration sprint later.
Proposed solution
Adopt logical Tailwind utilities + browser-native bidi handling as the convention in
apps/web:ml-*/mr-*→ms-*/me-*pl-*/pr-*→ps-*/pe-*left-*/right-*→start-*/end-*border-l-*/border-r-*→border-s-*/border-e-*text-left/text-right→text-start/text-endrounded-l-*/rounded-r-*→rounded-s-*/rounded-e-*dir=\"auto\"on assistant/user message content containers so Chromium picks the base direction from the first strong character per element. No JS detection needed.unicode-bidi: plaintextto message paragraphs (e.g. via a small utility class or directly on the markdown renderer's wrapper) so each line resolves independently. This is what fixes inlinepint/@user/ URLs getting shuffled inside Arabic sentences.dir=\"ltr\"+unicode-bidi: isolate, so source code stays LTR even when embedded inside an RTL message.eslint-plugin-tailwindcss.Why this matters
dir=\"auto\"and the chrome uses logical utilities, the renderer just works for RTL content without a dedicated feature.Smallest useful scope
A first PR that:
dir=\"auto\"and appliesunicode-bidi: plaintextto its paragraphs.dir=\"ltr\"; unicode-bidi: isolate.Sidebar.tsxor the chat message component) from physical to logical Tailwind utilities as a reference for the rest of the codebase.That alone makes Arabic conversations readable. The remaining components can be migrated incrementally, and a lint rule can be turned on once the codebase is clean.
Alternatives considered
dir=\"auto\"andunicode-bidi.Risks or tradeoffs
Examples or references
ms-*,me-*,ps-*,pe-*,start-*,end-*,text-start/end,border-s/e,rounded-s/e): https://tailwindcss.com/docs/margindir=\"auto\"reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dirContribution
All reactions