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 direction

Usage

<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

PropTypeDefaultDescription
classNamestring
dirDirectionValueReading 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.

On this page