Direction
DirectionProvider and useDirection for LTR / RTL layouts.
import { Button } from "@/components/ui/button";import { DirectionProvider } from "@/components/ui/direction";
function Card({ title, sub, join, share }: Record<string, string>) { return ( <div className="w-64 rounded-xl border border-border bg-card p-4"> <div className="text-sm font-medium">{title}</div> <div className="text-xs text-muted-foreground">{sub}</div> <div className="mt-3 flex gap-2"> <Button size="sm">{join}</Button> <Button size="sm" variant="secondary"> {share} </Button> </div> </div> );}
export default function Demo() { return ( <div className="flex flex-wrap gap-6"> <DirectionProvider direction="ltr"> <div dir="ltr"> <Card title="Magnificent Four" sub="4 tokens · rebalanced weekly" join="Join" share="Share" /> </div> </DirectionProvider> <DirectionProvider direction="rtl"> <div dir="rtl"> <Card title="مؤشر الأربعة العظماء" sub="٤ رموز · إعادة توازن أسبوعية" join="انضم" share="مشاركة" /> </div> </DirectionProvider> </div> );}<script setup lang="ts">import { Button } from "@/components/ui/button";import { DirectionProvider } from "@/components/ui/direction";</script>
<template> <div class="flex flex-wrap gap-6"> <DirectionProvider direction="ltr"> <div dir="ltr"> <div class="w-64 rounded-xl border border-border bg-card p-4"> <div class="text-sm font-medium">Magnificent Four</div> <div class="text-xs text-muted-foreground">4 tokens · rebalanced weekly</div> <div class="mt-3 flex gap-2"> <Button size="sm">Join</Button> <Button size="sm" variant="secondary">Share</Button> </div> </div> </div> </DirectionProvider> <DirectionProvider direction="rtl"> <div dir="rtl"> <div class="w-64 rounded-xl border border-border bg-card p-4"> <div class="text-sm font-medium">مؤشر الأربعة العظماء</div> <div class="text-xs text-muted-foreground">٤ رموز · إعادة توازن أسبوعية</div> <div class="mt-3 flex gap-2"> <Button size="sm">انضم</Button> <Button size="sm" variant="secondary">مشاركة</Button> </div> </div> </div> </DirectionProvider> </div></template><script lang="ts"> import { Button } from "$lib/components/ui/button"; import { DirectionProvider } from "$lib/components/ui/direction";</script>
{#snippet card(title: string, sub: string, join: string, share: string)} <div class="w-64 rounded-xl border border-border bg-card p-4"> <div class="text-sm font-medium">{title}</div> <div class="text-xs text-muted-foreground">{sub}</div> <div class="mt-3 flex gap-2"> <Button size="sm">{join}</Button> <Button size="sm" variant="secondary">{share}</Button> </div> </div>{/snippet}
<div class="flex flex-wrap gap-6"> <DirectionProvider direction="ltr"> <div dir="ltr"> {@render card("Magnificent Four", "4 tokens · rebalanced weekly", "Join", "Share")} </div> </DirectionProvider> <DirectionProvider direction="rtl"> <div dir="rtl"> {@render card("مؤشر الأربعة العظماء", "٤ رموز · إعادة توازن أسبوعية", "انضم", "مشاركة")} </div> </DirectionProvider></div>Installation
Section titled “Installation”npx shadcn@latest add @edmi-ui/directionpnpm dlx shadcn@latest add @edmi-ui/directionyarn dlx shadcn@latest add @edmi-ui/directionbunx shadcn@latest add @edmi-ui/directionPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @base-ui/reactTerminal window pnpm add @base-ui/reactTerminal window yarn add @base-ui/reactTerminal window bun add @base-ui/reactCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-vue@latest add @edmi-ui/directionpnpm dlx shadcn-vue@latest add @edmi-ui/directionyarn dlx shadcn-vue@latest add @edmi-ui/directionbunx shadcn-vue@latest add @edmi-ui/directionPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install reka-uiTerminal window pnpm add reka-uiTerminal window yarn add reka-uiTerminal window bun add reka-uiCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/direction.jsonpnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/direction.jsonyarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/direction.jsonbunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/direction.jsonPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Copy the code from Component source into your project and update the import paths to match your aliases.
import { Button } from "@/components/ui/button";
<div className="w-64 rounded-xl border border-border bg-card p-4"> <div className="text-sm font-medium">{title}</div> <div className="text-xs text-muted-foreground">{sub}</div> <div className="mt-3 flex gap-2"> <Button size="sm">{join}</Button> <Button size="sm" variant="secondary"> {share} </Button> </div></div><script setup lang="ts">import { Button } from "@/components/ui/button";import { DirectionProvider } from "@/components/ui/direction";</script>
<template> <div class="flex flex-wrap gap-6"> <DirectionProvider direction="ltr"> <div dir="ltr"> <div class="w-64 rounded-xl border border-border bg-card p-4"> <div class="text-sm font-medium">Magnificent Four</div> <div class="text-xs text-muted-foreground">4 tokens · rebalanced weekly</div> <div class="mt-3 flex gap-2"> <Button size="sm">Join</Button> <Button size="sm" variant="secondary">Share</Button> </div> </div> </div> </DirectionProvider> <DirectionProvider direction="rtl"> <div dir="rtl"> <div class="w-64 rounded-xl border border-border bg-card p-4"> <div class="text-sm font-medium">مؤشر الأربعة العظماء</div> <div class="text-xs text-muted-foreground">٤ رموز · إعادة توازن أسبوعية</div> <div class="mt-3 flex gap-2"> <Button size="sm">انضم</Button> <Button size="sm" variant="secondary">مشاركة</Button> </div> </div> </div> </DirectionProvider> </div></template><script lang="ts"> import { DirectionProvider } from "$lib/components/ui/direction";</script>
<div class="flex flex-wrap gap-6"> <DirectionProvider direction="ltr"> <div dir="ltr"> </div> </DirectionProvider> <DirectionProvider direction="rtl"> <div dir="rtl"> </div> </DirectionProvider></div>Component source
Section titled “Component source”export { DirectionProvider, useDirection,} from "@base-ui/react/direction-provider";<script setup lang="ts">import type { Direction } from 'reka-ui'import { ConfigProvider } from 'reka-ui'
// Same API as the React item (`direction`); Reka's ConfigProvider calls it `dir`.// It only provides context (no DOM node): set `dir` on a wrapper element too.defineProps<{ direction?: Direction }>()</script>
<template> <ConfigProvider :dir="direction ?? 'ltr'"> <slot /> </ConfigProvider></template>// Reka's composable: `useDirection()` -> ComputedRef<"ltr" | "rtl"> from the nearest provider.export { useDirection } from "reka-ui";export { default as DirectionProvider } from "./DirectionProvider.vue";<script lang="ts"> import type { Snippet } from "svelte"; import { type Direction, setDirectionContext } from "./context.js";
// Same API as the React item (`direction`). Provides context only (no DOM node): // set `dir` on a wrapper element too, and pass `useDirection().current` to Bits UI's `dir` props. let { direction = "ltr", children }: { direction?: Direction; children?: Snippet } = $props();
setDirectionContext(() => direction);</script>
{@render children?.()}import { getContext, setContext } from "svelte";
export type Direction = "ltr" | "rtl";
const DIRECTION_CONTEXT = Symbol("EDMI_DIRECTION_CONTEXT");
export function setDirectionContext(getDirection: () => Direction) { setContext(DIRECTION_CONTEXT, getDirection);}
// `useDirection()` -> `{ current }`: the direction of the nearest <DirectionProvider>, "ltr" without one.// `current` is a getter, so reading it inside `$derived` / the template stays reactive.// Pass a local override to mirror Base UI's `useDirection(localDir)`.export function useDirection(localDirection?: Direction): { readonly current: Direction;} { const getDirection = getContext<(() => Direction) | undefined>( DIRECTION_CONTEXT, ); return { get current() { return localDirection ?? getDirection?.() ?? "ltr"; }, };}import DirectionProvider from "./direction-provider.svelte";
export { type Direction, useDirection } from "./context.js";export { DirectionProvider };| Export | Notes |
|---|---|
DirectionProvider direction |
"ltr" | "rtl" — also set dir on <html> |
useDirection() |
returns the current direction |
✦ Edmi additions
Section titled “✦ Edmi additions”None — re-export of Base UI’s direction provider.
Vue / Svelte differences
Section titled “Vue / Svelte differences”- Vue:
DirectionProvider direction="rtl";useDirection()returns aComputedRef. - Svelte:
DirectionProvider direction="rtl";useDirection()returns{ current }.