Skip to content

ADR-0033: Right-to-left Studio — logical properties, dir from the registry, a Kumo patch until upstream

Context

No right-to-left language (Arabic, Hebrew, Persian, Urdu) can be added to Studio yet. DESIGN.md §1 lists RTL as a prerequisite. Measured on main at 7b1ec23 with node scripts/i18n-audit.ts:

Where Physical utilities (ml/mr/pl/pr/left/right/text-left/text-right/border-l/…) Logical utilities
apps/studio/src class names 34 (text-right 25, pl 4, text-left 3, ml 2) 0
packages/ui/src blocks 39 (ml 9, text-right 7, pl 6, text-left 6, …) 3
Kumo 2.14 dist (compiled classes) 239 12, plus 3 rtl: variants
Icons that point (Caret*/Arrow*Left/Right) 77 uses —

What already works:

  • the locale registry has dir and sets <html dir> together with lang (apps/studio/src/i18n/locales.ts, PR #152);
  • untrusted reader text uses dir="auto" (blocks/CommentText.tsx);
  • Base UI, under Kumo, supports direction through DirectionProvider, and Kumo re-exports it as @cloudflare/kumo/primitives/direction-provider.

What is missing:

  • Kumo styles. Its own styles are physical, so the sidebar, dialogs’ close buttons, input addons, table alignment, popovers’ offsets and the toolbar would not mirror.
  • Icons. Nothing mirrors directional icons.

Options

A. Where Kumo’s physical styles get fixed

Option Pros Cons
A1. Upstream first, with a pnpm patch until it lands (as @cloudflare__kumo@2.14.0.patch does today) No fork. The fix benefits Cloudflare’s own RTL plans. The patch is mechanical (ml-→ms-, left-→start-, …) and one file. A patch over compiled dist must be redone on every Kumo upgrade until upstream ships, and the class list in dist is long (239).
A2. Fork Kumo Full control Owning a design system that Cloudflare evolves weekly. Breaks “Kumo via @cloudhal/ui” and the kumo-design skill.
A3. A wrapper layer: CSS overrides under [dir=rtl] in @cloudhal/ui/styles.css that flip margins, paddings and positions of Kumo’s classes No change to Kumo’s files Hundreds of overrides that silently drift from Kumo’s classes, and specificity fights. It fixes classes, not components (popover placement is still physical).
A4. Wait for Kumo to support RTL No work Unknown timeline; RTL languages stay blocked

B. dir handling

  • <html dir> comes from the registry, which is done.
  • DirectionProvider wraps the app at the root (main.tsx), with direction={LOCALE_REGISTRY[locale].dir}, so Base UI’s arrows and placement follow it.
  • dir="auto" stays on user content (comments, titles shown verbatim, editor bodies), because a Turkish Studio can show Arabic comments.

C. Icon mirroring

Option Pros Cons
C1. A DirectionalIcon block (or a directional prop on Kumo-wrapped buttons) that sets Phosphor’s mirrored when dir is rtl, used for icons that mean a direction: back, forward, next, previous, breadcrumbs’ carets, “open in new”, indent Explicit: only meaning-carrying icons flip, never clocks, media play or checkmarks (Material’s guidance) 77 call sites to review once
C2. CSS rtl:-scale-x-100 on every Caret*/Arrow* One rule Flips icons that must not flip (a chart’s trend arrow, “sort ascending”)

D. Studio’s and the blocks’ own 73 physical classes

A lint rule (design lint, like i18n-format) forbids physical utilities in apps/studio/src and packages/ui/src from now on, and a codemod converts the 73 occurrences. Directional exceptions (a chart axis, a slider that means “left”) carry i18n-ignore-style reasons.

  1. A1:
    • convert Kumo’s physical classes with a pnpm patch, generated by a script so each Kumo upgrade can re-run it;
    • file the upstream issue the same day (kumo-upstream-notes.md §7);
    • drop the patch when Kumo ships logical properties.
  2. B: DirectionProvider at the root, driven by the registry. Keep dir="auto" on user content.
  3. C1: a DirectionalIcon block in @cloudhal/ui and a reviewed list of directional icons.
  4. D: convert Studio’s and the blocks’ 34 + 39 physical utilities with a codemod, and add a design-lint rule against new ones now. The rule costs nothing even before any RTL language exists.
  5. Verification: pnpm design:shots with an RTL pseudo-locale, a mirrored variant of Phase 5’s pseudo-locale with dir="rtl" and an Arabic font stack, at 1440 and 390 px, before the first real RTL language.
  6. Order: D and B first (cheap, no new language needed), then A1 and C1 when an RTL language is scheduled.

Consequences

  • Positive:
    • RTL languages become possible;
    • logical properties also make the code clearer (“start” means the reading start);
    • the lint keeps Studio honest without waiting.
  • Negative:
    • a second Kumo patch to maintain until upstream;
    • a one-time review of 77 icon uses.
  • Risks:
    • Kumo’s compiled class names change between versions and the patch script drifts. Mitigation: a test that fails when the patch no longer applies, as for the current patch.
    • Charts (ECharts) need their own RTL settings (axis and legend placement), out of this ADR’s scope; noted for the analytics screens.

Decisions (2026-10-18)

The owner delegated the open questions; decided in the session that coordinates the i18n work:

  • First right-to-left language: Arabic (ar), with Western digits. The registry entry is keyed ar, and Studio formats with the tag ar-u-nu-latn. Studio shows ids, versions, revisions and code next to numbers, and Western digits keep them readable together. Arabic-Indic digits (nu-arab) may become a person’s preference later.
  • Order:
    • A1: the generated Kumo patch, with a test that fails when it no longer applies, and the upstream issue text ready for the owner to file;
    • C1: DirectionalIcon, converting only icons that mean a direction;
    • then the Arabic catalogs, verified with SHOTS_LOCALE=ar pnpm design:shots at 1440 and 390 px.
  • ECharts: its right-to-left settings (axis side, legend order) are a follow-up if the Arabic step does not cover them.

Open questions

None left from this ADR; the questions below were answered above.

  • (answered) Does Cloudflare plan RTL in Kumo? The upstream issue (kumo-upstream-notes.md §7) asks; the patch does not wait for the answer.
  • (answered) Which RTL language first, which numerals? Arabic, Western digits (ar-u-nu-latn).