3.5 KiB
useDirection
(no submodules)
Purpose
useDirection() returns the writing direction ('ltr' / 'rtl') for
the active locale. Composes useLocale (so it inherits the underlying
useSyncExternalStore subscription) and runs the locale through
@suaveplan/i18n's getTextDirection helper. The single-source-of-truth
for which locales are RTL lives in the i18n core's RTL_LOCALES set —
the React surface does not duplicate the list.
The hook is the canonical primitive for direction-sensitive UI: setting
<html dir="...">, mirroring icon strips, swapping margin-left for
margin-right in a CSS module, and so on. A locale change like
setLocale('ar-AE') flips the result to 'rtl' on the same React
commit cycle as the bus emission, so the UI re-mirrors atomically with
the new translations.
Features
- Returns
{ direction, locale }— both kept in sync with the active locale. 'ltr'/'rtl'resolution via the i18n core'sgetTextDirection.directiondefaults to'ltr'on the production no-Provider fallback (the safer default for unknown locales).- Memoised on the locale string so a no-op re-render does not re-call
getTextDirection. - Re-renders on
languageChangedvia the inheriteduseLocalesubscription.
Usage: Basic Example
import { useDirection } from "@suaveplan/react-i18n";
export function ChatBubble(props: { readonly children: React.ReactNode }) {
const { direction } = useDirection();
return (
<div
dir={direction}
style={{ textAlign: direction === "rtl" ? "right" : "left" }}
>
{props.children}
</div>
);
}
Usage: Advanced Example
For document-level mirroring set the <html dir> attribute from a
top-level effect that mirrors the hook's output. The pattern below
keeps the markup in sync without needing every component to be
direction-aware.
import { useEffect } from "react";
import { useDirection } from "@suaveplan/react-i18n";
export function HtmlDirectionSync(): null {
const { direction, locale } = useDirection();
useEffect(() => {
const root = document.documentElement;
if (locale !== undefined) root.lang = locale;
root.dir = direction;
}, [direction, locale]);
return null;
}
API Reference
useDirection(): UseDirectionReturn
- Returns:
{ direction, locale }.direction: 'ltr' | 'rtl'— derived fromgetTextDirection(locale). Defaults to'ltr'whenlocale === undefined.locale: string | undefined— current active locale, mirrored fromuseLocale().locale.
- Throws:
ReactI18nError(REACT_I18N.NO_PROVIDER)outside a<TranslationProvider>in dev mode (inherited fromuseLocale → useI18n).
Implementation Notes
- The lookup is wrapped in
useMemokeyed on the locale string.getTextDirectionis cheap (a singleSet.hasafter a string split), but the memo also keeps the returned object reference stable across re-renders that did not change the locale, which keepsReact.memo-wrapped descendants from re-rendering. - The hook deliberately delegates the RTL list to
@suaveplan/i18ninstead of duplicating it. New RTL scripts added to the upstreamRTL_LOCALEStable propagate automatically — no React-side maintenance required. - The fallback to
'ltr'on the no-Provider production path matches the broader package contract: end-users see degraded but non-broken UI when configuration is missing.