RTL Support
First-class right-to-left layout support for Arabic, Hebrew, Persian, and other RTL languages.
Hello World
LTRThis is a left-to-right layout example.
import { DirectionProvider } from "@/components/ui/direction-provider";
export default function RootLayout({ children }) {
return (
<DirectionProvider defaultDirection="rtl">
{children}
</DirectionProvider>
);
}Overview#
AniUI components support RTL layouts through two mechanisms:
- Logical Tailwind properties — components use
ps-*,pe-*,ms-*,me-*instead of physicalpl-*/pr-*properties, which NativeWind maps to React Native'spaddingStart/paddingEnd. - DirectionProvider — a context provider that wraps
I18nManagerand provides auseDirection()hook for reading and setting direction.
Setup#
Install the DirectionProvider component and wrap your root layout:
npx @aniui/cli add direction-providerimport { DirectionProvider } from "@/components/ui/direction-provider";
export default function RootLayout({ children }) {
return (
<DirectionProvider defaultDirection="rtl">
{children}
</DirectionProvider>
);
}Reading Direction#
Use the useDirection() hook to access the current direction from any child component.
import { useDirection } from "@/components/ui/direction-provider";
function MyComponent() {
const { isRTL, direction } = useDirection();
return (
<View className={cn("flex-row", isRTL && "flex-row-reverse")}>
<Text>Content adapts to {direction}</Text>
</View>
);
}Logical Properties#
AniUI components use logical CSS properties that automatically adapt to RTL layouts. When writing custom styles, prefer logical properties:
| Physical (avoid) | Logical (prefer) | Description |
|---|---|---|
pl-* / pr-* | ps-* / pe-* | Padding start/end |
ml-* / mr-* | ms-* / me-* | Margin start/end |
text-left / text-right | text-start / text-end | Text alignment |
left-* / right-* | start-* / end-* | Position |
border-l / border-r | border-s / border-e | Border start/end |
Flipping Icons#
Directional icons like back arrows need to be flipped in RTL mode. Use scaleX: -1 to mirror them:
import { useDirection } from "@/components/ui/direction-provider";
function BackButton() {
const { isRTL } = useDirection();
return (
<Pressable onPress={goBack}>
<Svg
width={24} height={24}
viewBox="0 0 24 24"
style={isRTL ? { transform: [{ scaleX: -1 }] } : undefined}
>
<Path d="M15 18l-6-6 6-6" />
</Svg>
</Pressable>
);
}Component Examples#
Components that use logical properties adapt automatically. No code changes needed.
InputGroup#
// In LTR: [$][___input___]
// In RTL: [___input___][$] (automatic via logical properties)
<InputGroup>
<InputGroupAddon align="start">
<InputGroupText>$</InputGroupText>
</InputGroupAddon>
<InputGroupInput placeholder="Amount" />
</InputGroup>Combobox Multi-select#
// In LTR: [Tag1 ✕] [Tag2 ✕]
// In RTL: [✕ Tag1] [✕ Tag2] (automatic via logical properties)
<Combobox
multiple
selectedValues={["tag1", "tag2"]}
options={options}
onSelectedValuesChange={setSelected}
/>Field#
// Label and description alignment flips automatically
<Field orientation="horizontal">
<FieldLabel>البريد الإلكتروني</FieldLabel>
<Input placeholder="أدخل بريدك الإلكتروني" />
<FieldDescription>سنرسل لك رمز التحقق</FieldDescription>
</Field>Dynamic Direction Toggle#
Build a settings screen that lets users switch direction:
import { useDirection } from "@/components/ui/direction-provider";
import { SegmentedControl } from "@/components/ui/segmented-control";
import { Field, FieldLabel, FieldDescription } from "@/components/ui/field";
function LanguageSettings() {
const { direction, setDirection } = useDirection();
return (
<Field>
<FieldLabel>Layout Direction</FieldLabel>
<SegmentedControl
values={["LTR", "RTL"]}
selectedIndex={direction === "ltr" ? 0 : 1}
onChange={(index) => {
setDirection(index === 0 ? "ltr" : "rtl");
}}
/>
<FieldDescription>
Changing direction requires restarting the app.
</FieldDescription>
</Field>
);
}Important#
Calling setDirection updates the React context value immediately for re-renders, but the full layout direction flip via I18nManager.forceRTL() requires an app restart. This is a React Native platform limitation.
For the best user experience, persist the direction preference and apply it before the app renders on next launch.
Component Support#
All AniUI components use logical Tailwind properties and support RTL layouts out of the box.
| Category | Components | RTL | Notes |
|---|---|---|---|
| Layout | Field, InputGroup, Card, Grid, SafeArea | Full | Logical properties throughout |
| Inputs | Input, Textarea, SearchBar, PasswordInput, MaskedInput, PhoneInput, NumberInput, Combobox, Select | Full | Icons, addons, and borders flip correctly |
| Display | Text, Badge, Chip, Label, Kbd, Price, Avatar, Image | Full | Text alignment handled by NativeWind |
| Feedback | Alert, Banner, Toast, Spinner, Progress, Skeleton, ConnectionBanner | Full | Dismiss buttons and icons flip |
| Navigation | Header, TabBar, Tabs, Stepper, ProgressSteps, Pagination | Full | Back arrows need icon flipping (see above) |
| Overlays | Dialog, AlertDialog, Popover, Tooltip, HoverCard, BottomSheet, DropdownMenu, ContextMenu | Full | Portal content follows direction context |
| Actions | Button, Toggle, ToggleGroup, FAB, Switch, Checkbox, RadioGroup | Full | FAB positions use start/end |
| Data | List, Table, Timeline, ChatBubble, StatCard, Rating, Calendar | Full | Timeline and chat bubbles flip sides |
| Providers | DirectionProvider, ThemeProvider | Full | Core RTL infrastructure |
| Charts | AreaChart, BarChart, LineChart, PieChart, RadarChart, RadialChart | Partial | SVG coordinates are always physical; axis labels may need manual adjustment |
| Gesture | Slider, Drawer, SwipeableListItem, Carousel | Partial | Gesture direction and inline styles use physical properties by design |
Full = all styles use logical properties, automatic RTL support.
Partial = works in RTL but some visual aspects (SVG coordinates, gesture directions) use physical properties by necessity.
Accessibility#
- Screen readers automatically respect
I18nManagerdirection settings. - Logical properties ensure touch targets and content flow correctly for RTL users.
- Supports Arabic, Hebrew, Persian, Urdu, and other RTL languages.
- Works with both Expo SDK 54 (NativeWind v4) and SDK 55 (NativeWind v5).
