RTL

Every gsxui component renders correctly in a right-to-left document. Set dir="rtl" and the components you've already vendored adapt on their own — no RTL variant to install or opt into.

Get started

Set dir="rtl" on <html> for a fully right-to-left page, or on any subtree — a single Arabic or Hebrew panel inside a left-to-right app, for example:

<html lang="ar" dir="rtl">
  ...
</html>

How it works

Four mechanisms carry direction through the component set, all driven by the ancestor's resolved dir:

  • Logical Tailwind classes. Components use ms-*/me-*,start-*/end-*, and text-start/text-end instead of physical ml-*/left-*, so spacing and alignment mirror for free.
  • Directional icons. Chevrons and arrows that encode a left/right meaning carryrtl:rotate-180, flipping only under an RTL ancestor.
  • Direction-aware floating positioning. Popover, dropdown-menu, select, tooltip, and the rest of the floating-UI family resolve their placement in JS at position time, so "start"-aligned content opens on the correct physical side.
  • Mirrored keyboard semantics. Arrow keys in menus, tabs, carousel, calendar, and the other roving-focus components mirror by meaning per WAI-ARIA — under RTL, ArrowLeft means "toward the next item" and opens submenus, the way ArrowRight does under LTR.

Two deliberate exceptions. input-otp's digit group stays pinned dir="ltr": a code like 482915 reads left-to-right even inside an RTL form, matching real Arabic and Hebrew UIs. And Sheet, Drawer, and Sidebar keep their side="left"/side="right" propphysical, matching shadcn's data-side contract — a side="right"sidebar stays on the visual right under either direction, while everything inside it still mirrors normally.

Try it out

An Arabic sign-in card: unmodified Card, Label, Input, and Button, wrapped in dir="rtl".

تسجيل الدخول
أدخل بيانات حسابك للمتابعة

ليس لديك حساب؟ إنشاء حساب

// Package rtl holds the site's example gsx components demonstrating gsxui
// components under dir="rtl" — not tied to a single ui/ component the way
// the other site/examples packages are.
package rtl

import "github.com/gsxhq/gsxui/ui"

// Login is an Arabic sign-in card rendered under dir="rtl": every part —
// Card, Label, Input, Button — adapts through logical Tailwind properties
// alone, no RTL-specific markup of its own. This is the /docs/rtl page's
// "Try it out" demo.
component Login() {
	<div dir="rtl" lang="ar" class="max-w-sm">
		<ui.Card>
			<ui.CardHeader>
				<ui.CardTitle>تسجيل الدخول</ui.CardTitle>
				<ui.CardDescription>أدخل بيانات حسابك للمتابعة</ui.CardDescription>
			</ui.CardHeader>
			<ui.CardContent>
				<form class="flex flex-col gap-4">
					<div class="flex flex-col gap-2">
						<ui.Label for="rtl-login-email">البريد الإلكتروني</ui.Label>
						<ui.Input
							id="rtl-login-email"
							type="email"
							name="email"
							placeholder="[email protected]"
							autocomplete="email"
							required
						/>
					</div>
					<div class="flex flex-col gap-2">
						<ui.Label for="rtl-login-password">كلمة المرور</ui.Label>
						<ui.Input id="rtl-login-password" type="password" name="password" autocomplete="current-password" required/>
					</div>
					<ui.Button type="submit" class="w-full">دخول</ui.Button>
				</form>
			</ui.CardContent>
			<ui.CardFooter>
				<p class="text-sm text-muted-foreground">ليس لديك حساب؟ إنشاء حساب</p>
			</ui.CardFooter>
		</ui.Card>
	</div>
}

More RTL variants live on their own component pages: Calendar, Pagination, and Sidebar each register an "RTL" example alongside their other demos.

Fonts

The site's own Latin type is Geist. For Arabic content, pair it with Noto Sans Arabic (a UI sans) or Noto Naskh Arabic (better for longer prose). Load the Arabic font as a fallback rather than replacing Geist outright, so Latin text — brand names, code — keeps rendering in Geist inside an RTL document.