| name | rtl-ui |
| description | Implements right-to-left (RTL) UI patterns for Arabic interfaces using Tailwind CSS, covering layout direction, icon mirroring, typography, and spacing constraints for bidirectional applications |
RTL UI Development Standards
This skill provides comprehensive guidelines for building right-to-left (RTL) user interfaces, primarily targeting Arabic language support with Tailwind CSS.
🚨 CRITICAL REQUIREMENTS - READ FIRST
MANDATORY Rules (Application Will Break if Violated)
❌ NEVER USE THESE CLASSES - WILL CAUSE RTL BUGS:
// BANNED - Physical properties
ml-*, mr-*, pl-*, pr-* // ❌ NEVER
left-*, right-* // ❌ NEVER
text-left, text-right // ❌ NEVER
rounded-l-*, rounded-r-* // ❌ NEVER
border-l-*, border-r-* // ❌ NEVER
✅ ALWAYS USE THESE INSTEAD - MANDATORY:
// REQUIRED - Logical properties
ms-*, me-* // ✅ REQUIRED (margin-inline-start/end)
ps-*, pe-* // ✅ REQUIRED (padding-inline-start/end)
start-*, end-* // ✅ REQUIRED (positioning)
text-start, text-end // ✅ REQUIRED (alignment)
rounded-s-*, rounded-e-* // ✅ REQUIRED (border-radius)
border-s-*, border-e-* // ✅ REQUIRED (borders)
⚠️ ZERO TOLERANCE POLICY:
- Every
ml-*must bems-* - Every
pl-*must beps-* - Every
text-leftmust betext-start - NO EXCEPTIONS - Even for "temporary" code
Next.js 14 Server Actions - MANDATORY PATTERN
❌ ANTI-PATTERN - NEVER DO THIS:
// app/login/page.tsx
'use client';
export default function LoginPage() {
// ❌ WRONG - Server action inside client component file
async function loginAction(formData: FormData) {
'use server'; // ❌ Mixed directives in same file
// ...
}
return <form action={loginAction}>...</form>
}
✅ REQUIRED PATTERN - ALWAYS DO THIS:
// app/actions/login.ts
'use server'; // ✅ Dedicated server action file
export async function loginAction(formData: FormData) {
const supabase = await createClient()
// ... implementation
}
// app/login/page.tsx
'use client'; // ✅ Separate client component file
import { loginAction } from '@/app/actions/login'
export default function LoginPage() {
return <form action={loginAction}>...</form>
}
📁 REQUIRED File Structure:
app/
├── actions/ ✅ MANDATORY - All server actions here
│ ├── login.ts ('use server')
│ ├── register.ts ('use server')
│ └── ...
├── (auth)/
│ ├── login/
│ │ └── page.tsx ('use client')
│ └── register/
│ └── page.tsx ('use client')
🔒 RULE: One directive per file
- Files with
'use server'→ Only server code - Files with
'use client'→ Only client code - NEVER mix both in same file
Core Principles
1. Directional Layout System
Always use logical properties over physical properties:
// ❌ WRONG - Physical properties
<div className="ml-4 pl-6 text-left">
// ✅ CORRECT - Logical properties (auto-flips in RTL)
<div className="ms-4 ps-6 text-start">
Tailwind RTL-Safe Utilities:
ms-*/me-*instead ofml-*/mr-*(margin-inline-start/end)ps-*/pe-*instead ofpl-*/pr-*(padding-inline-start/end)start-*/end-*instead ofleft-*/right-*(positioning)text-start/text-endinstead oftext-left/text-rightrounded-s-*/rounded-e-*instead ofrounded-l-*/rounded-r-*border-s-*/border-e-*instead ofborder-l-*/border-r-*
2. HTML Direction Attribute
Set the direction at the root level:
<!-- For Arabic content -->
<html dir="rtl" lang="ar">
<!-- For English content -->
<html dir="ltr" lang="en">
Dynamic direction switching:
// React/Next.js example
<html dir={locale === 'ar' ? 'rtl' : 'ltr'} lang={locale}>
3. Icon Mirroring Strategy
Icons that MUST mirror in RTL:
- Arrows: → ← ↗ ↙
- Chevrons: › ‹
- Navigation: back, forward, next, previous
- Directional actions: undo, redo, reply, forward (email)
- Timeline and progress indicators
- List indicators and bullet points
Icons that NEVER mirror:
- Media controls: play ▶, pause ⏸, stop ⏹
- Shopping cart 🛒
- Magnifying glass 🔍
- Checkmarks ✓
- Close/X buttons ✕
- Clocks and time 🕐
- Symmetrical icons: +, ×, gear ⚙
Implementation:
// Using Lucide React or similar icon library
import { ChevronRight } from 'lucide-react';
// Option 1: CSS transform
<ChevronRight className="rtl:scale-x-[-1]" />
// Option 2: Conditional rendering
{isRTL ? <ChevronLeft /> : <ChevronRight />}
// Option 3: Rotate class (for arrows)
<ArrowRight className="rtl:rotate-180" />
4. Arabic Typography Rules
Font Selection:
- Use Arabic-optimized fonts: Cairo, Almarai, Tajawal, Noto Sans Arabic
- Ensure proper font stack:
'Cairo', 'Segoe UI Arabic', -apple-system, system-ui
Font Sizing:
- Arabic text needs 10-15% larger font size for equivalent readability
- Line height: Use 1.7-1.8 for Arabic (vs 1.5-1.6 for English)
/* Tailwind config extension */
.font-arabic {
font-family: 'Cairo', 'Segoe UI Arabic', sans-serif;
line-height: 1.75;
}
/* Apply via CSS */
html[dir="rtl"] {
font-size: 105%; /* Slightly larger base size */
}
Letter Spacing:
// ❌ NEVER use letter-spacing with Arabic
<h1 className="tracking-wide">مرحبا</h1>
// ✅ Default spacing only
<h1>مرحبا</h1>
5. Spacing and Layout Constraints
Flexbox Direction:
// ❌ WRONG - Hardcoded direction
<div className="flex flex-row">
// ✅ CORRECT - Auto-reverses in RTL
<div className="flex flex-row">
{/* Flex items automatically reverse in RTL context */}
</div>
// For explicit control when needed
<div className="flex flex-row rtl:flex-row-reverse">
Grid Layouts:
// Grids work naturally in RTL - no changes needed
<div className="grid grid-cols-3 gap-4">
{/* Items flow naturally based on dir attribute */}
</div>
Asymmetric Spacing:
// ❌ WRONG - Physical spacing
<div className="mr-4 ml-2">
// ✅ CORRECT - Logical spacing
<div className="me-4 ms-2">
6. Forms and Inputs
🚨 MANDATORY Form Pattern:
// ✅ REQUIRED - Complete form input with RTL support
<div className="space-y-6">
<div>
<label
htmlFor="email"
className="block text-start mb-2 font-medium" // ✅ block + text-start
>
{locale === 'ar' ? 'البريد الإلكتروني' : 'Email'}
</label>
<input
id="email"
name="email"
type="email"
dir="auto" // ✅ MANDATORY - Detects input direction
className="w-full ps-4 pe-4 py-3 text-start rounded-lg border" // ✅ ps-4 pe-4, NOT px-4
placeholder={locale === 'ar' ? 'أدخل بريدك الإلكتروني' : 'Enter your email'}
required
/>
</div>
<div>
<label
htmlFor="password"
className="block text-start mb-2 font-medium"
>
{locale === 'ar' ? 'كلمة المرور' : 'Password'}
</label>
<input
id="password"
name="password"
type="password"
dir="auto" // ✅ MANDATORY
className="w-full ps-4 pe-4 py-3 text-start rounded-lg border" // ✅ Logical padding
placeholder={locale === 'ar' ? 'أدخل كلمة المرور' : 'Enter password'}
required
/>
</div>
<button
type="submit"
className="w-full py-3 bg-primary text-white rounded-lg"
>
{locale === 'ar' ? 'تسجيل الدخول' : 'Sign In'}
</button>
</div>
// ❌ WRONG - Common mistakes
<input className="px-4" /> // ❌ NOT px-4
<input className="pl-4 pr-10" /> // ❌ NOT pl-/pr-
<label className="text-left" /> // ❌ NOT text-left
<input /> // ❌ Missing dir="auto"
📋 Form Input Checklist (MANDATORY):
- All labels have
className="block text-start" - All inputs have
dir="auto"attribute - All inputs use
ps-*andpe-*(NEVERpx-*,pl-*,pr-*) - All inputs have
text-startclass - All placeholders are localized
- Button text is localized
7. Positioning and Absolute Elements
// ❌ WRONG - Physical positioning
<div className="absolute right-4 top-4">
// ✅ CORRECT - Logical positioning
<div className="absolute end-4 top-4">
// Dropdowns and tooltips
<div className="absolute start-0 top-full mt-2">
{/* Will appear on correct side in both LTR/RTL */}
</div>
8. Border Radius and Decorative Elements
// ❌ WRONG
<div className="rounded-l-lg rounded-r-sm">
// ✅ CORRECT
<div className="rounded-s-lg rounded-e-sm">
// Asymmetric borders
<div className="border-s-4 border-e-2 border-primary">
Common Patterns
Navigation Menu
<nav className="flex gap-4">
<Link href="/" className="flex items-center gap-2">
<Home className="rtl:scale-x-[-1]" />
<span>{t('home')}</span>
</Link>
<Link href="/about" className="flex items-center gap-2">
<span>{t('about')}</span>
<ChevronRight className="rtl:rotate-180" />
</Link>
</nav>
Card Layouts
<div className="flex gap-4 p-6">
<img src={avatar} className="w-12 h-12 rounded-full" />
<div className="flex-1 text-start">
<h3 className="font-semibold">{name}</h3>
<p className="text-sm text-gray-600">{description}</p>
</div>
<button className="ms-auto">
<MoreVertical />
</button>
</div>
Breadcrumbs
<nav className="flex items-center gap-2">
{breadcrumbs.map((item, i) => (
<>
<Link href={item.href}>{item.label}</Link>
{i < breadcrumbs.length - 1 && (
<ChevronRight className="rtl:rotate-180 text-gray-400" />
)}
</>
))}
</nav>
Modal Dialogs
<div className="fixed inset-0 flex items-center justify-center">
<div className="bg-white rounded-lg p-6 max-w-md w-full">
<div className="flex items-start gap-4">
<AlertCircle className="text-red-500 flex-shrink-0" />
<div className="flex-1 text-start">
<h2 className="font-bold mb-2">{t('warning')}</h2>
<p className="text-gray-600">{t('message')}</p>
</div>
<button className="ms-auto">
<X />
</button>
</div>
</div>
</div>
Testing Checklist
Before marking RTL implementation as complete:
🚨 CRITICAL - Zero Tolerance Items:
- ZERO instances of
ml-*,mr-*,pl-*,pr-*in entire codebase - ZERO instances of
left-*,right-*for positioning - ZERO instances of
text-left,text-right - ZERO instances of
rounded-l-*,rounded-r-* - ZERO instances of
border-l-*,border-r-* - ALL server actions in separate
app/actions/files - NO files with both 'use client' and 'use server'
✅ Required Implementations:
-
dir="rtl"andlang="ar"attributes set on<html>tag - All physical direction classes replaced with logical equivalents
- Directional icons properly mirrored or rotated
- Arabic font applied with appropriate line-height
- NO
letter-spacingon Arabic text - Form inputs have
dir="auto"attribute - Form labels have
block text-startclasses - Form inputs use
ps-*andpe-*(NOTpx-*) - Navigation flows in correct direction
- Dropdown menus and tooltips positioned correctly
- Asymmetric spacing (margins, padding) uses logical properties
- Tables use
text-start/text-end(NEVERtext-left/text-right) - Absolute positioned elements use
start-*/end-* - Tested on actual RTL content (not just English text flipped)
- Responsive breakpoints work in RTL mode
🔍 Code Search Commands (Run These):
# Search for banned classes - ALL must return 0 results
grep -r "ml-" src/
grep -r "mr-" src/
grep -r "pl-" src/
grep -r "pr-" src/
grep -r "text-left" src/
grep -r "text-right" src/
grep -r "left-" src/
grep -r "right-" src/
# Search for correct classes - Should find many results
grep -r "ms-" src/
grep -r "me-" src/
grep -r "ps-" src/
grep -r "pe-" src/
grep -r "text-start" src/
grep -r "text-end" src/
Common Mistakes to Avoid
- Using transform: scaleX(-1) on text - Never flip text itself
- Applying letter-spacing to Arabic - Breaks Arabic ligatures
- Hardcoding left/right in JavaScript - Use getBoundingClientRect() carefully
- Forgetting dir="auto" on user input fields - Breaks mixed content
- Over-mirroring icons - Play buttons should never mirror
- Using physical properties "temporarily" - Always use logical from the start
- Testing only with flipped English - Arabic has unique rendering needs
- ❌ Mixing 'use client' and 'use server' in same file - Separate into different files
- ❌ Using
px-*on form inputs - Always useps-*andpe-* - ❌ Using
text-lefton tables - Always usetext-start
Resources
Progressive Enhancement
For older browsers without logical property support, consider a fallback:
/* tailwind.config.js - Add RTL plugin */
module.exports = {
plugins: [
require('tailwindcss-rtl'),
],
}
This ensures comprehensive RTL support across all browsers and contexts.