Hướng chữ RTL
Yugen UI hỗ trợ ngôn ngữ viết từ phải sang trái (Arabic, Hebrew, Persian…) bằng một prop dir và quy tắc chỉ dùng utility logical.
Bật RTL
Một prop dir trên YugenProvider: thẻ bao (hoặc <html> khi applyToDocument) nhận dir, và DirectionProvider của Radix truyền hướng chữ cho mọi component.
// Toàn ứng dụng: ghi dir="rtl" lên <html> và cấp hướng chữ cho Radix
<YugenProvider applyToDocument dir="rtl" theme="light">
<App />
</YugenProvider>
// Hoặc chỉ một vùng (ví dụ xem trước bản dịch)
<YugenProvider dir="rtl" lang="ar" className="rounded-xlarge p-5">
<Breadcrumb items={[{ label: "الرئيسية" }, { label: "المستندات" }]} />
</YugenProvider><!-- Đặt sẵn trong HTML để trang không nhảy hướng khi tải -->
<html lang="ar" dir="rtl" data-theme="light">- CSS: thuộc tính
dirđảo flex, grid, text-align mặc định và mọi utility logical (ms-*,ps-*,start-*…). - Hành vi: Tabs, Menu (menu con mở sang trái), RadioGroup, Slider, ToggleGroup, ScrollArea, Toolbar, Tree, List, Carousel, TagPicker, InputOTP, Rating đọc hướng từ
DirectionProviderđể đảo phím mũi tên và chiều kéo. - Overlay: Popover, Tooltip, HoverCard, Dialog, Drawer, Menu và listbox gắn
dircủa provider lên bề mặt dù render trong portal; Toaster củawithToasterdùng vị trí logicbottom-endnên tự sang góc trái khi RTL.
Ví dụ trực tiếp
Đổi hướng chữ của khung bên dưới; thử Tab rồi dùng phím mũi tên trên Tabs và Slider — ← / → đổi vai trò khi RTL.
مرحبا بك في يوغن
<YugenProvider dir="rtl" lang="ar" className="flex flex-col gap-4 rounded-2xlarge border border-stroke-2 p-6">
<Breadcrumb items={[{ label: "الرئيسية" }, { label: "المستندات" }, { label: "التقارير" }]} />
<Input aria-label="ابحث" placeholder="ابحث…" contentBefore={<Search20Regular />} rootClassName="w-64" />
<Switch label="الإشعارات" defaultChecked />
<Slider label="مستوى الصوت" showValue defaultValue={[30]} rootClassName="max-w-sm" />
<Pagination pageCount={10} defaultPage={3} />
<Button appearance="primary" icon={<ArrowRight20Regular className="rtl:-scale-x-100" />} iconPosition="after">
التالي
</Button>
</YugenProvider>Utility logical
Quy tắc cho tác giả component: không dùng hướng vật lý cho bố cục. Utility logical tự đảo theo dir, không cần variant rtl:.
| Không dùng (vật lý) | Dùng (logical) | CSS |
|---|---|---|
ml-* / mr-* | ms-* / me-* | margin-inline-start / end |
pl-* / pr-* | ps-* / pe-* | padding-inline-start / end |
left-* / right-* | start-* / end-* | inset-inline-start / end |
border-l / border-r | border-s / border-e | border-inline-start / end |
rounded-l-* / rounded-r-* | rounded-s-* / rounded-e-* | border-start-start-radius… |
rounded-tl-* / rounded-tr-* | rounded-ss-* / rounded-se-* | border-start-start / start-end-radius |
text-left / text-right | text-start / text-end | text-align: start / end |
space-x-* với margin tay | gap-* | gap không có hướng |
Ngoại lệ hợp lệ: căn giữa bằng left-1/2 -translate-x-1/2 (đối xứng), và nội dung luôn LTR như mã nguồn, số điện thoại, URL — bọc bằng <bdi> hoặc dir="ltr" để thuật toán bidi không đảo thứ tự ký tự.
اتصل بنا: +84 912 345 678
الرمز: npm run dev
Lật icon & transform
Icon biểu thị hướng (tiến, lùi, gửi, thụt lề) phải lật trong RTL; icon biểu thị vật thể hay khái niệm thì giữ nguyên.
dir="ltr"
- Mũi tên tiến / lùilật
- Chevron điều hướnglật
- Gửilật
- Tìm kiếmgiữ
- Dấu tíchgiữ
- Phát mediagiữ
dir="rtl"
- Mũi tên tiến / lùilật
- Chevron điều hướnglật
- Gửilật
- Tìm kiếmgiữ
- Dấu tíchgiữ
- Phát mediagiữ
{/* Icon chỉ hướng: lật theo chiều đọc */}
<ChevronRight16Regular className="rtl:-scale-x-100" />
<Button icon={<ArrowLeft20Regular className="rtl:-scale-x-100" />}>Quay lại</Button>
{/* Transform vật lý: viết hai nhánh */}
<span className="translate-x-5.5 rtl:-translate-x-5.5" />
{/* Chevron mở / đóng: lật trước, rồi xoay ngược chiều trong RTL */}
<ChevronRight20Regular className="rtl:-scale-x-100 group-data-[state=open]:rotate-90 rtl:group-data-[state=open]:-rotate-90" />Biến thể rtl: của Tailwind khớp phần tử nằm trong bất kỳ tổ tiên nào có dir="rtl", nên hoạt động cả với YugenProvider lồng. Dùng nó cho mọi giá trị vật lý không có bản logical: translate-x, rotate, scale-x, gradient có góc, background-position.
Phím mũi tên
Component Radix và các component Yugen có điều hướng ngang đã tự đảo ← / →. Khi tự viết, đọc hướng bằng useDirection().
import { useDirection } from "@radix-ui/react-direction";
/** ← / → theo chiều đọc: trong RTL, ArrowLeft là "tiến". */
export function useInlineArrowKeys(onPrev: () => void, onNext: () => void) {
const dir = useDirection(); // "ltr" | "rtl" — lấy từ YugenProvider
return (event: React.KeyboardEvent) => {
const nextKey = dir === "rtl" ? "ArrowLeft" : "ArrowRight";
const prevKey = dir === "rtl" ? "ArrowRight" : "ArrowLeft";
if (event.key === nextKey) {
event.preventDefault();
onNext();
} else if (event.key === prevKey) {
event.preventDefault();
onPrev();
}
};
}useYugen().dir cho cùng giá trị nhưng useDirection() của @radix-ui/react-direction cũng hoạt động bên ngoài Yugen (bất kỳ DirectionProvider nào). ↑ / ↓, Home / End không đổi theo hướng chữ.
Kiểm thử
RTL hỏng thường lộ ra ở khoảng cách, icon và phím — kiểm tra cả ba.
- Bật nút LTR / RTL trên thanh trên cùng của site docs và lướt qua trang component của bạn.
- So khoảng cách hai bên: icon trong nút, padding của ô nhập, vạch chọn của Nav / Tabs phải đổi phía.
- Đi bằng bàn phím: ← / → trên Tabs, Slider, Toolbar, menu con, Carousel phải theo chiều đọc.
- Mở overlay (Menu, Popover, Tooltip, Drawer start / end) và Toast — chúng nằm trong portal.
- Tìm utility vật lý còn sót trong mã nguồn:
# Liệt kê class vật lý cần xem lại (bỏ qua kết quả căn giữa left-1/2)
rg -n "\b(ml|mr|pl|pr|left|right|border-l|border-r|rounded-l|rounded-r|text-left|text-right)-" src/components- Dùng ms/me/ps/pe/start/end/border-s/border-e/rounded-s/rounded-e/text-start.
- Lật icon chỉ hướng bằng rtl:-scale-x-100.
- Đặt lang cùng dir để trình đọc màn hình đọc đúng ngôn ngữ.
- Không lật logo, dấu tích, kính lúp, icon media.
- Không viết nhánh dir === 'rtl' trong JS cho thứ CSS logical làm được.
- Không giả định ArrowRight luôn là “tiếp theo”.