Skip to content

Direction

Sets the reading direction for everything inside it. It writes the dir attribute and gives React Aria the matching locale, so arrow keys and logical CSS flip together.

Layoutv0.1.0experimentalWCAG 2.2 AAView spec
كما يظهر في الفاتورة.
بيانات الحساب.
import { Direction, Tab, TabList, TabPanel, Tabs, TextField } from "@rdloom/react";

export default function DirectionRtlFormExample() {
  return (
    <div className="flex w-full justify-center">
      <Direction direction="rtl" lang="ar" className="flex w-full max-w-sm flex-col gap-4">
        <TextField label="الاسم" description="كما يظهر في الفاتورة." />
        <Tabs>
          <TabList aria-label="الإعدادات">
            <Tab id="profile">الملف الشخصي</Tab>
            <Tab id="billing">الفواتير</Tab>
            <Tab id="team">الفريق</Tab>
          </TabList>
          <TabPanel id="profile">بيانات الحساب.</TabPanel>
          <TabPanel id="billing">طرق الدفع والفواتير.</TabPanel>
          <TabPanel id="team">أعضاء الفريق وأدوارهم.</TabPanel>
        </Tabs>
      </Direction>
    </div>
  );
}

Installation

npx rdloom add direction

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes. It needs react-aria-components; add --install to install them.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/direction.json

Works, but without upgrade tracking.

Usage

import { Direction, Tab, TabList, TabPanel, Tabs, TextField } from "@rdloom/react";

<div className="flex w-full justify-center">
  <Direction direction="rtl" lang="ar" className="flex w-full max-w-sm flex-col gap-4">
    <TextField label="الاسم" description="كما يظهر في الفاتورة." />
    <Tabs>
      <TabList aria-label="الإعدادات">
        <Tab id="profile">الملف الشخصي</Tab>
        <Tab id="billing">الفواتير</Tab>
        <Tab id="team">الفريق</Tab>
      </TabList>
      <TabPanel id="profile">بيانات الحساب.</TabPanel>
      <TabPanel id="billing">طرق الدفع والفواتير.</TabPanel>
      <TabPanel id="team">أعضاء الفريق وأدوارهم.</TabPanel>
    </Tabs>
  </Direction>
</div>

Side by side

Account details.
بيانات الحساب.
import { Direction, Tab, TabList, TabPanel, Tabs, TextField } from "@rdloom/react";

export default function DirectionSideBySideExample() {
  return (
    <div className="flex w-full justify-center">
      <div className="grid w-full max-w-3xl gap-8 sm:grid-cols-2">
        <Direction direction="ltr" className="flex flex-col gap-4">
          <TextField label="Name" />
          <Tabs>
            <TabList aria-label="Settings, left to right">
              <Tab id="a">Profile</Tab>
              <Tab id="b">Billing</Tab>
            </TabList>
            <TabPanel id="a">Account details.</TabPanel>
            <TabPanel id="b">Payment methods.</TabPanel>
          </Tabs>
        </Direction>
        <Direction direction="rtl" lang="ar" className="flex flex-col gap-4">
          <TextField label="الاسم" />
          <Tabs>
            <TabList aria-label="الإعدادات">
              <Tab id="a">الملف الشخصي</Tab>
              <Tab id="b">الفواتير</Tab>
            </TabList>
            <TabPanel id="a">بيانات الحساب.</TabPanel>
            <TabPanel id="b">طرق الدفع.</TabPanel>
          </Tabs>
        </Direction>
      </div>
    </div>
  );
}

Nested

Direction here: rtl

Direction here: ltr

Addresses are always written left to right.
import { Direction, TextField, useDirection } from "@rdloom/react";

function Current() {
  const { direction } = useDirection();
  return <p className="text-sm text-[var(--rd-color-text-muted)]">Direction here: {direction}</p>;
}

export default function DirectionNestedExample() {
  return (
    <div className="flex w-full justify-center">
      <Direction direction="rtl" lang="ar" className="flex w-full max-w-sm flex-col gap-4 rounded-[var(--rd-radius-control)] border border-[var(--rd-color-border-default)] p-4">
        <Current />
        <TextField label="الاسم" />
        <Direction direction="ltr" lang="en" className="flex flex-col gap-2 border-s-2 border-[var(--rd-color-border-strong)] ps-3">
          <Current />
          <TextField label="Email address" description="Addresses are always written left to right." />
        </Direction>
      </Direction>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
direction

Reading direction of the subtree.

"ltr" | "rtl""ltr"
locale

BCP 47 locale for the subtree, such as ar-EG. Defaults to en-US for ltr and ar for rtl. Pick one whose script matches the direction.

stringnone
childrenrequired

The content that takes the direction.

nodenone

Accessibility

Role none, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

  • In rtl, Left Arrow moves forward and Right Arrow moves back in tabs, radio groups and sliders

Screen readers announce

  • Not announced itself; text in the subtree is read in its own order

What your code must do

  • The dir attribute is set on the wrapper so the browser lays out text and logical CSS correctly
  • The locale is passed to React Aria so keyboard navigation matches the visual order
  • Set lang on content in another language so screen readers pick the right voice

Guidelines

Use it when

  • A page or section written in a right to left language such as Arabic or Hebrew
  • A single block that differs from the page direction
  • Previewing how a layout flips

Avoid it when

  • The whole app has one direction: set dir on the html element and the provider once

Don't

  • Using rtl only to mirror the layout while the text stays left to right
  • Mixing physical CSS such as margin-left inside: use logical properties so it flips