LOKE Design System
Hooks

useDirection

Resolve layout/text direction from local override or a context provider. Defaults to "ltr" when neither is provided.

useDirection

useDirection returns the current layout direction "ltr" or "rtl". It supports:

  • Local override: pass a preferred direction directly to the hook for one‑off usage.
  • Context provider: wrap parts of your app with DirectionProvider to set direction for a subtree.
  • Sensible default: returns "ltr" if no local or provider value is present.

This hook is useful when building components that need to mirror layout for right‑to‑left languages (e.g., Arabic, Hebrew). It keeps direction resolution explicit and easy to compose.


API

type Direction = 'ltr' | 'rtl';

/**
 * Resolve direction with optional local override, then provider, else "ltr".
 */
function useDirection(localDir?: Direction): Direction;

Provider

type Direction = 'ltr' | 'rtl';

type DirectionProviderProps = {
  dir: Direction;
  children?: React.ReactNode;
};

function DirectionProvider(props: DirectionProviderProps): JSX.Element;

Provider props

Prop

Type


Usage

import * as React from 'react';
import { DirectionProvider, useDirection } from '@loke/ui/use-direction';

function MirroredArrow() {
  const dir = useDirection(); // resolves from provider or "ltr"
  const isRtl = dir === 'rtl';

  return (
    <span aria-hidden>
      {isRtl ? '←' : '→'}
    </span>
  );
}

export function App() {
  // Set RTL globally for a subtree
  return (
    <DirectionProvider dir="rtl">
      <div className="flex items-center gap-2">
        <span>Next</span>
        <MirroredArrow />
      </div>
    </DirectionProvider>
  );
}

2) Local override (no provider needed)

import { useDirection } from '@loke/ui/use-direction';

function InlineChevron({ forceDir }: { forceDir?: 'ltr' | 'rtl' }) {
  // local override takes precedence
  const dir = useDirection(forceDir);
  return <span aria-hidden>{dir === 'rtl' ? '«' : '»'}</span>;
}

export function Example() {
  return (
    <div className="flex flex-col gap-2">
      <div>
        Default (no provider, no override): <InlineChevron />
      </div>
      <div>
        Forced RTL: <InlineChevron forceDir="rtl" />
      </div>
      <div>
        Forced LTR: <InlineChevron forceDir="ltr" />
      </div>
    </div>
  );
}

3) Toggle direction at runtime

import * as React from 'react';
import { DirectionProvider, useDirection } from '@loke/ui/use-direction';

function Indicator() {
  const dir = useDirection();
  return <span className="text-sm text-muted-foreground">dir: {dir}</span>;
}

export function DirectionToggleDemo() {
  const [dir, setDir] = React.useState<'ltr' | 'rtl'>('ltr');

  return (
    <DirectionProvider dir={dir}>
      <div className="flex items-center gap-3">
        <Indicator />
        <button
          type="button"
          className="rounded border px-2 py-1"
          onClick={() => setDir((d) => (d === 'ltr' ? 'rtl' : 'ltr'))}
        >
          Toggle
        </button>
      </div>
    </DirectionProvider>
  );
}

Behavior

  • Precedence:
    1. Hook argument localDir (if provided)
    2. Nearest DirectionProvider value
    3. Fallback "ltr"
  • Pure computation: the hook does not mutate DOM attributes. Use it to branch behavior or classes in components.
  • Composability: nest DirectionProvider to override direction for sub‑trees (e.g., embedded widgets or localized sections).

Patterns and tips

  • Pair with conditional classes:
    const dir = useDirection();
    const justifyClass = dir === 'rtl' ? 'justify-start' : 'justify-end';
  • Prefer DirectionProvider high in the tree to avoid passing direction props everywhere.
  • Use local override for one‑off rendering (icons/text that differ in RTL).

Import

import { useDirection, DirectionProvider } from '@loke/ui/use-direction';