Skip to content

Direction

Sets the writing direction for a subtree and exposes it to the components that need to know which way is forward.

Sets the writing direction for a subtree and exposes it to the components that need to know which way is forward. Compose it from the exported registry parts so local content and behaviour stay in the application while the visual contract stays token-driven.

import { Avatar } from "@/registry/bases/newt/ui/avatar"
import { DirectionProvider } from "@/registry/bases/newt/ui/direction"
import { MessageComposer } from "@/registry/bases/newt/ui/message-composer"
import {
  MessageGroup,
  MessageGroupAuthor,
  MessageGroupAvatar,
  MessageGroupBody,
  MessageGroupContent,
  MessageGroupHeader,
  MessageGroupTime,
} from "@/registry/bases/newt/ui/message-group"

/*
 * The same components as anywhere else, with one attribute above them. Nothing
 * here is direction-aware: the logical properties do the work.
 *
 * Placeholder names only — no real account, and no Discord asset.
 */
export default function DirectionDemo() {
  return (
    <DirectionProvider
      dir="rtl"
      className="flex w-full max-w-md flex-col gap-2"
    >
      <MessageGroup>
        <MessageGroupAvatar>
          <Avatar>ل</Avatar>
        </MessageGroupAvatar>
        <MessageGroupBody>
          <MessageGroupHeader>
            <MessageGroupAuthor>ليلى</MessageGroupAuthor>
            <MessageGroupTime dateTime="2026-09-07T12:04">
              اليوم 12:04
            </MessageGroupTime>
          </MessageGroupHeader>
          <MessageGroupContent>
            كل شيء يعمل من اليمين إلى اليسار.
          </MessageGroupContent>
        </MessageGroupBody>
      </MessageGroup>
      <MessageComposer channelName="عام" />
    </DirectionProvider>
  )
}
<script setup lang="ts">
import { Avatar } from "~~/registry/bases/newt/ui/avatar"
import { DirectionProvider } from "~~/registry/bases/newt/ui/direction"
import { MessageComposer } from "~~/registry/bases/newt/ui/message-composer"
import {
  MessageGroup,
  MessageGroupAuthor,
  MessageGroupAvatar,
  MessageGroupBody,
  MessageGroupContent,
  MessageGroupHeader,
  MessageGroupTime,
} from "~~/registry/bases/newt/ui/message-group"

/*
 * The same components as anywhere else, with one attribute above them. Nothing
 * here is direction-aware: the logical properties do the work.
 *
 * Placeholder names only — no real account, and no Discord asset.
 */
</script>

<template>
  <DirectionProvider dir="rtl" class="flex w-full max-w-md flex-col gap-2">
    <MessageGroup>
      <MessageGroupAvatar>
        <Avatar>ل</Avatar>
      </MessageGroupAvatar>
      <MessageGroupBody>
        <MessageGroupHeader>
          <MessageGroupAuthor>ليلى</MessageGroupAuthor>
          <MessageGroupTime date-time="2026-09-07T12:04">
            اليوم 12:04
          </MessageGroupTime>
        </MessageGroupHeader>
        <MessageGroupContent>
          كل شيء يعمل من اليمين إلى اليسار.
        </MessageGroupContent>
      </MessageGroupBody>
    </MessageGroup>
    <MessageComposer channel-name="عام" />
  </DirectionProvider>
</template>

Installation

pnpm dlx newtui@latest add direction
npx newtui@latest add direction
yarn dlx newtui@latest add direction
bunx newtui@latest add direction

Copy the source into your project

"use client"

import * as React from "react"

/*
 * Every component is written with logical properties, so a right-to-left tree
 * needs no per-component override — only a `dir` attribute somewhere above it.
 * This is that attribute, plus the context a component reads when it has to
 * make a decision the CSS cannot: which side a popover flips to, which arrow
 * key advances a list.
 */
export type Direction = "ltr" | "rtl"

const DirectionContext = React.createContext<Direction>("ltr")

export interface DirectionProviderProps extends React.ComponentProps<"div"> {
  dir: Direction
}

const DirectionProvider = React.forwardRef<
  HTMLDivElement,
  DirectionProviderProps
>(({ dir, children, ...props }, ref) => (
  <DirectionContext.Provider value={dir}>
    <div ref={ref} dir={dir} {...props}>
      {children}
    </div>
  </DirectionContext.Provider>
))
DirectionProvider.displayName = "DirectionProvider"

/**
 * The direction the nearest provider set, or `"ltr"` when there is none — the
 * same default the document has.
 */
function useDirection(): Direction {
  return React.useContext(DirectionContext)
}

export { DirectionProvider, useDirection }
<script setup lang="ts">
import { provide, toRef } from "vue"

import { DIRECTION_KEY, type Direction } from "./useDirection"

/*
 * Every component is written with logical properties, so a right-to-left tree
 * needs no per-component override — only a `dir` attribute somewhere above it.
 * This is that attribute, plus the injection a component reads when it has to
 * make a decision the CSS cannot.
 */
const props = defineProps<{ dir: Direction }>()

provide(DIRECTION_KEY, toRef(props, "dir"))
</script>

<template>
  <div :dir="props.dir">
    <slot />
  </div>
</template>
import { inject, ref, type InjectionKey, type Ref } from "vue"

export type Direction = "ltr" | "rtl"

export const DIRECTION_KEY: InjectionKey<Ref<Direction>> = Symbol("newt-dir")

/**
 * The direction the nearest provider set, or `"ltr"` when there is none — the
 * same default the document has.
 */
export function useDirection(): Ref<Direction> {
  return inject(DIRECTION_KEY, ref<Direction>("ltr"))
}
export { default as DirectionProvider } from "./DirectionProvider.vue"
export { DIRECTION_KEY, useDirection, type Direction } from "./useDirection"

Update the import paths

The files import @/lib/utils and sibling components through the aliases in your components.json. Point them at wherever those live in your project.

Usage

import { Direction } from "@/components/ui/direction"

export function Example() {
  return <Direction />
}
<script setup lang="ts">
import { DirectionProvider } from "@/components/ui/direction"
</script>

<template>
  <DirectionProvider />
</template>

API reference

DirectionProvider

PropType
dir?Direction

Required dir value.

TypeDirection

The registry exports Direction, DirectionProvider. Parts without a table accept the native attributes for the element they render; React uses className, while Vue uses class and fallthrough attributes.

Accessibility

Preserve the native semantics of the rendered elements and pass through ARIA attributes when the surrounding context needs a label or description. Any interactive child needs a visible focus indicator, and meaning must not rely on colour alone.

Tokens

Direction reads its colours, radii and motion from the --newt-* tokens installed with the library. Override a token and every component that reads it follows, including this one — see the token layer.