Direction
Reading direction for everything below it.
Sets the reading direction for everything below it. Rows, start/end insets and horizontal padding mirror natively, so a right-to-left locale needs one wrapper rather than a mirrored copy of every screen.
The flip is the layout engine's own, which is why this is a component and not a bare context: direction is a style, so a subtree is the unit it applies to. Unlike forcing the whole process right-to-left, it takes effect on the next frame, can be scoped to part of a screen, and can be nested — an identifier or a phone number can stay left-to-right inside a right-to-left page.
Installation
Direction ships with the library — no separate install.
import { Direction, useDirection } from 'panelui-native';Or copy the source into your project, to own and edit it:
npx panelui-cli@latest add directionUsage
<Direction dir="rtl">
<App />
</Direction>Examples
At the root
Wrap the app once. Direction fills its parent by default, which is what you want here — it is standing in for the screen.
<PanelUIProvider>
<Direction dir={locale.rtl ? 'rtl' : 'ltr'}>
<App />
</Direction>
</PanelUIProvider>Around one section
Inside a screen the default flex-1 is wrong — it would fill the space instead of hugging the rows. flex-none wins over it, since className merges with later classes taking precedence.
<Direction dir="rtl" className="w-full flex-none">
<Item.Group>
<Item>
<Item.Media variant="icon">
<BellIcon size={16} />
</Item.Media>
<Item.Content>
<Item.Title>الإشعارات</Item.Title>
<Item.Description>Badges, sounds, banners</Item.Description>
</Item.Content>
<ChevronRightIcon size={16} />
</Item>
</Item.Group>
</Direction>An island that must not flip
Nesting resets the direction for one subtree and nothing else. A phone number, an account ID or a code snippet reads the same way in every locale — mirroring it makes it wrong rather than localised.
<Direction dir="rtl">
<Text>رقم الهاتف</Text>
<Direction dir="ltr" className="flex-none">
<Text>+1 (555) 010-4477</Text>
</Direction>
</Direction>Flipping maths the layout cannot
Anything measured in raw pixels rather than laid out — a drag translation, an indicator offset, the direction a sweep travels — has to negate itself. useDirection() is safe to call with no provider mounted: it falls back to the device's own setting.
function Scrubber({ width }: { width: number }) {
const dir = useDirection();
const pan = Gesture.Pan().onChange((event) => {
const dx = dir === 'rtl' ? -event.changeX : event.changeX;
progress.value = clamp(progress.value + dx / width, 0, 1);
});
return <GestureDetector gesture={pan}>{/* … */}</GestureDetector>;
}API Reference
Direction
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
dir | DirectionValue | — | Reading direction for this subtree. Defaults to the nearest enclosing Direction, or to the device when there is none — so a nested provider with no dir inherits rather than resetting to left-to-right. |
Every part also accepts the underlying React Native props (ViewProps or TextProps) and a className for Tailwind utilities.
Notes
Nesting inherits: a Direction with no dir takes the value from the nearest one above it, and falls back to the device when there is none. So a provider added for structure does not silently reset a subtree to left-to-right.
What it does not mirror is anything not laid out by flexbox. Gesture translations, animated offsets in pixels and the direction of a sweep or a shimmer all keep their sign — read useDirection() and negate them yourself. The layout flip covers rows, insets and padding, which is the large majority of a screen.
It does not replace localised strings, date formats or number formats. It mirrors the furniture; the content is still yours to translate.