UI Audit Project: Fixing a Wrongly Mirrored Interface
A hands-on closing project: we take a real dashboard that was auto-mirrored with dir=”rtl” alone, diagnose all thirteen errors by type, then fix them one by one using everything we learned in this series.
Word count: ~2,500 · Reading time: 14 minutes
UI Audit Project: Fixing a Wrongly Mirrored Interface
Building step by step — diagnose the errors first, then rebuild the interface on solid ground
A note for the reader: This article is the hands-on closing project of the series. You can read it on its own, but it draws on concepts built across the previous three articles: Logical Properties, Fixed Components, and Visual Psychology.
In this article from Zy Yazan, we reach the real test: does everything we learned in the previous three articles translate into actual diagnostic ability? The answer is yes — and we’re going to prove it by fixing a genuinely broken interface, one line of code at a time.
The interface we’re working with: a task management app dashboard that was converted to Arabic using only dir="rtl" with no additional handling — the most common scenario in real projects. We’ll identify the errors, classify them, then fix them in the right order.
Step 1: Inventory the Errors Before Touching the Code
The first rule of any audit: don’t write a single line of code until the inventory is complete. A developer who starts fixing before fully understanding the problem risks patching a surface bug that’s hiding ten deeper ones underneath.
The method: open the interface with dir="rtl", take a screenshot, then classify every problem you spot into one of two categories:
- Under-flip error: Something that should have flipped and didn’t — caused by leftover physical properties.
- Over-flip error: Something that flipped when it should have held its position — caused by a missing explicit exception.
In the dashboard we’re auditing, we found thirteen errors. We’ll work through the most significant ones, grouped by type.
Step 2: Fix the Under-Flip Errors
These are the easiest to diagnose: you see an element still behaving as if the page is LTR even though it’s in RTL mode. The cause is always a leftover physical CSS property.
Error 1 — Sidebar border on the wrong side
The app’s sidebar has a decorative border that visually separates it from the main content area. In the original code:
/* ❌ Original code — physical */
.sidebar {
border-right: 1px solid #e0e0e0; /* border always on the right */
padding-left: 0;
padding-right: 20px;
}
In LTR the sidebar sits on the left, so a border on its right side makes sense as a separator. When the interface flipped and the sidebar moved to the right, the border stayed on the right too — now sitting on the sidebar’s outer edge instead of its inner dividing edge.
/* ✅ Fix — logical */
.sidebar {
border-inline-end: 1px solid #e0e0e0; /* border always at the end of the sidebar */
padding-inline: 20px 0;
}
Error 2 — Icon margins are reversed
Each nav item in the sidebar has an icon followed by a label. The space between them is hardcoded with a physical property:
/* ❌ Original code */
.nav-item .icon {
margin-right: 12px; /* spacing after icon in LTR */
}
In RTL the icon moved to the right of the label, so the correct gap is now on its left — but the code still places it on the right, leaving the icon pressed against the outer edge with no breathing room and the label floating away from it.
/* ✅ Fix */
.nav-item .icon {
margin-inline-end: 12px; /* spacing after icon in reading direction */
}
Error 3 — Tooltip appears on the wrong side
Absolutely positioned tooltips use left or right to set their position:
/* ❌ Original code */
.tooltip {
position: absolute;
left: calc(100% + 8px); /* appears to the right of the element in LTR */
top: 50%;
transform: translateY(-50%);
}
In RTL the tooltip should appear to the left of the element — but it still appears on the right, either running off the screen edge or overlapping the sidebar.
/* ✅ Fix */
.tooltip {
position: absolute;
inset-inline-start: calc(100% + 8px); /* appears after the element in reading direction */
top: 50%;
transform: translateY(-50%);
}
Error 4 — Table text alignment is hardcoded
The data tables in the dashboard use an explicit text-align: left instead of relying on inheritance:
/* ❌ Original code */
.data-table td {
text-align: left; /* overrides RTL inheritance, forces text left */
}
/* ✅ Fix */
.data-table td {
text-align: start; /* follows reading direction automatically */
}
Step 3: Fix the Over-Flip Errors
These errors are harder to spot but have more impact on user experience. The interface flipped elements that should have held their ground.
Error 5 — Task audio player fully mirrored
The app lets users attach audio recordings to tasks. The player inherited dir="rtl" from the page and its progress bar flipped:
/* ❌ Problem: player inherits full RTL */
/* Progress bar runs from the right, time display is reversed */
/* ✅ Fix: lock only the time axis */
.task-audio-player .progress-bar,
.task-audio-player .time-display {
direction: ltr;
unicode-bidi: isolate;
}
/* Arabic label stays Arabic — don't touch it */
.task-audio-player .track-title {
/* inherits RTL from the page — correct */
}
Error 6 — Pagination arrows point the wrong way
The pagination bar uses SVG arrow icons. Because the icons weren’t explicitly handled, Flexbox reordered the buttons — but the arrow icons themselves didn’t flip, so “Next” now points left and “Previous” points right:
/* ❌ Problem: Flexbox reversed button order automatically
but the SVG icons weren't flipped — arrows point wrong way */
/* ✅ Fix: visual flip for directional icons only */
[dir="rtl"] .pagination .arrow-next svg,
[dir="rtl"] .pagination .arrow-prev svg {
transform: scaleX(-1);
}
/* ⚠️ Do NOT flip play, delete, or settings icons */
/* These are universal symbols — they stay as-is */
Error 7 — Skeleton animation runs against reading direction
The loading animation on task cards moves left to right — opposite to the Arabic reading direction — producing the subtle visual discomfort we covered in the previous article:
/* ✅ Fix: reverse shimmer direction in RTL */
[dir="rtl"] .skeleton-card {
animation-name: shimmer-rtl;
}
@keyframes shimmer-rtl {
from { background-position: 200% 0; }
to { background-position: -200% 0; }
}
Error 8 — Time-series chart is mirrored
The dashboard includes a productivity chart showing user output over days. The charting library inherited dir="rtl" and reversed the time axis — newest data on the left, oldest on the right, opposite to scientific convention:
/* ❌ Problem: chart container inherited dir="rtl" */
/* ✅ Fix: lock the chart container direction */
.productivity-chart-wrapper {
direction: ltr; /* time X-axis is a scientific convention — don't flip */
}
/* Arabic labels inside the chart need direction restored */
.productivity-chart-wrapper .chart-label {
direction: rtl; /* restore RTL for text only */
unicode-bidi: isolate;
}
⚠️ Note on third-party chart libraries
Some charting libraries (Chart.js, Recharts, ApexCharts) have built-in RTL support via config options. Check the library’s documentation before adding direction: ltr manually — there may be an rtl: false or direction: 'ltr' option in the config object that’s cleaner and safer.
Step 4: Fix CTA Placement Based on the Visual Path
This type of error doesn’t show up when you look at the code — it shows up when you step back and look at the whole interface and ask: is the primary action button where the user’s eye actually goes?
In our interface, the “Create New Task” button sat in the bottom-left corner of the screen. In LTR apps, the floating action button (FAB) conventionally lives in the bottom-right — and when the page flipped, it automatically moved to bottom-left. But as we learned in Article 3, the bottom-left corner is the most visually neglected zone for Arabic users:
/* ❌ FAB — auto-flipped to bottom-left */
.fab-button {
position: fixed;
bottom: 24px;
/* Was: right: 24px in LTR */
/* After flip: left: 24px ← dead zone for Arabic users */
}
/* ✅ Fix: place it at the bottom-right in RTL */
/* Bottom-right is visually warmer than bottom-left for Arabic users */
.fab-button {
position: fixed;
bottom: 24px;
inset-inline-end: 24px; /* right in RTL, left in LTR */
}
Notice the interesting outcome: in LTR, the button sits on the right (the end of the inline axis). In RTL, the button also sits on the right — because right is now the start of the inline axis, which is the hot zone. Using inset-inline-end instead of a hardcoded right value delivers the correct result in both directions.
Step 5: The Complete Fix File
This is the complete correction file that addresses all thirteen errors in the dashboard, organized with comments explaining the reasoning behind each decision:
/* ════════════════════════════════════════════
RTL Fix File — Task Management Dashboard
RTL Interface Design Guide — Zy Yazan
════════════════════════════════════════════ */
/* ── 1. Under-flip fixes (leftover physical properties) ── */
.sidebar {
border-inline-end: 1px solid #e0e0e0;
padding-inline: 20px 0;
}
.nav-item .icon {
margin-inline-end: 12px;
}
.tooltip {
position: absolute;
inset-inline-start: calc(100% + 8px);
top: 50%;
transform: translateY(-50%);
}
.data-table td,
.data-table th {
text-align: start;
}
.task-card .badge {
inset-inline-end: 12px; /* was: right: 12px */
inset-block-start: 12px; /* was: top: 12px */
}
.dropdown-menu {
inset-inline-start: 0; /* was: left: 0 */
}
.form-input {
padding-inline: 12px 40px; /* icon at the logical end */
}
.form-input-icon {
inset-inline-end: 12px; /* was: right: 12px */
}
/* ── 2. Over-flip fixes (fixed components that got mirrored) ── */
/* Audio player: lock the time axis */
.task-audio-player .progress-bar,
.task-audio-player .time-display {
direction: ltr;
unicode-bidi: isolate;
}
/* Pagination: visual flip for directional arrows only */
[dir="rtl"] .pagination .arrow-next svg,
[dir="rtl"] .pagination .arrow-prev svg {
transform: scaleX(-1);
}
/* Loading animation: reverse shimmer direction */
[dir="rtl"] .skeleton-card {
animation-name: shimmer-rtl;
}
@keyframes shimmer-rtl {
from { background-position: 200% 0; }
to { background-position: -200% 0; }
}
/* Productivity chart: lock time axis, restore RTL for labels */
.productivity-chart-wrapper {
direction: ltr;
}
.productivity-chart-wrapper .chart-label {
direction: rtl;
unicode-bidi: isolate;
}
/* Circular status indicator: no change needed */
/* .status-indicator — fixed by nature, leave it alone */
/* ── 3. CTA placement fix based on visual path ── */
.fab-button {
position: fixed;
bottom: 24px;
inset-inline-end: 24px;
}
/* Manual review reminders: */
/* Action icons (delete, edit, settings) — do NOT flip */
/* Logo and page header — review manually */
/* ════════════════════════════════════════════ */
The Audit Checklist — Ready for Your Next Project
Run this checklist before shipping any RTL project:
| # | What to check | Tool |
|---|---|---|
| 1 | Search CSS files for left / right / margin-left / padding-right |
grep or VS Code Regex |
| 2 | Check every media player: progress bar fills from the left | Visual check + DevTools |
| 3 | Every nav arrow points the right way (Next = right in RTL) | Visual check |
| 4 | Time-series charts: oldest data left, newest data right | Visual check |
| 5 | Skeleton animation moves right → left in RTL | DevTools Animation panel |
| 6 | Tooltips and dropdowns appear on the correct side | Interactive check |
| 7 | Primary CTA is in the hot zone (right or center) | Visual check |
| 8 | Action icons (delete, edit) were not flipped | Visual check |
| 9 | Numeric strings (timestamps, amounts) isolated from bidi context | Text inspection |
| 10 | Bottom-left corner has no important content | Visual check |
The checklist doesn’t replace understanding — but it keeps you from forgetting what you understand. Save it as rtl-checklist.md in your project and add to it every time you discover a new pattern.
AI-Assisted Auditing — What It Can and Can’t Do
With large language models now widely available, a practical question comes up: can you delegate part of an RTL audit to an AI model? The honest answer: yes for specific tasks, no for others.
| Task | Claude | GPT-4o | Gemini | Note |
|---|---|---|---|---|
| Find physical CSS properties and replace with logical ones | ✓ Good | ✓ Good | ✓ Good | Mechanical task — all models handle it reliably |
| Distinguish fixed components from flippable ones | ✓ Good | ~ Moderate | ~ Moderate | Needs sufficient context in the prompt |
| Generate a complete CSS fix file from an error list | ✓ Good | ✓ Good | ✓ Good | Review the output — models can over-fix |
| Visual inspection of a mirrored interface to spot breakage | ✓ With screenshot | ✓ With screenshot | ✓ With screenshot | Attaching a screenshot is essential for accuracy |
| Estimating the visual scan path and optimal CTA placement | ~ Relative | ~ Relative | ~ Relative | Final call stays with the designer — no substitute |
| Verifying actual browser behavior and user interaction | ✗ | ✗ | ✗ | No replacement for testing in a real browser |
The practical summary: all three models are useful for clear, mechanical tasks — finding physical properties, generating fix code, and building checklists. But they all need a tight prompt that gives them the right context, and they all need a human review before applying any output to production code.
The Prompt — Ready to Copy and Use
This prompt is built for the dashboard project we worked through in this article. Copy it, paste your actual code into the marked slots, and attach a screenshot of the mirrored interface if you can:
You are an expert in RTL interface design and CSS engineering for Arabic.
I have a [app type: dashboard / store / blog] interface
that was converted to Arabic using only dir="rtl" on the html tag with no additional handling.
Task:
1. Review the code below and identify every physical CSS property (containing left/right)
that needs to be replaced with a logical property.
2. Identify any components that should stay in LTR mode inside the RTL page,
with a short justification for each (temporal / quantitative / universal convention).
3. Write a complete CSS fix file organized in two sections:
- Section 1: Under-flip fixes (physical → logical properties)
- Section 2: Over-flip fixes (fixed components that need direction: ltr)
4. Add a short comment above each CSS rule explaining the reasoning.
Hard constraints:
- Do NOT flip: action icons (delete / edit / settings)
- Do NOT flip: media players and their progress bars
- Do NOT flip: charts with a time-based X axis
- Do NOT flip: numbers and dates (isolate with unicode-bidi: isolate only)
--- CSS ---
[Paste your CSS file or the section to audit here]
--- Related HTML (optional but helpful) ---
[Paste the HTML structure for the main components here]
A General Framework for Writing RTL Prompts
A good prompt for any RTL audit task needs four elements, in order:
- Context: The type of app and the current flip method (just
dir="rtl"? A separate rtl.css file? A utility framework like Tailwind?) - Explicit constraints: What must not be touched — without constraints, models tend to over-fix.
- Output format: Organized CSS file? Numbered list? Inline comments? Specify this upfront.
- A screenshot: Attaching one significantly improves diagnostic accuracy — the model sees the visual breakage directly instead of inferring it from code.
And an optional fifth element that meaningfully improves results: an example of the desired output format. If you attach a sample of how you want the fix file structured, the model will follow that pattern consistently across all the rules it generates.
Series Wrap-Up
Across four articles, we covered the complete journey: from the conceptual difference between physical and logical properties, to the exceptions that intentionally break the flipping rule, to the science of how Arabic users actually see the screen, and finally to a broken interface we fixed line by line.
The principle running through the whole series is simple: building a good Arabic interface doesn’t mean translating a Western interface — it means building an interface that understands where its user starts, what they already know, and where they expect to find what they need. Code is a tool. Logical properties are a tool. Fixed components are a thinking framework. But all of these tools serve one goal: an Arabic user who uses an interface that feels like it was made for them, not reformatted for them.
References:
- Material Design RTL audit guidelines: Material Design — Bidirectionality
- Apple’s guide to testing RTL interfaces: Apple HIG — Right to Left
- RTL inspection in Chrome DevTools: Chrome DevTools
- Our complete series — RTL Interface Design Guide: Article 1: CSS Logical Properties
— RTL Interface Design Guide —
Previous article: 3 — Visual Psychology: How Arabic Users Read the Screen
Final article: 4 — UI Audit Project: Fixing a Wrongly Mirrored Interface
Related series:
Hybrid Text Processing Guide |
Financial Data Localization Guide |
Web 3.0 & AI Localization Workshop
Zy Yazan © 2026
Localization Series
RTL Interface Design Guide — 4 Articles
Series: RTL Interface Design Guide — 4 Articles | Zy Yazan Platform © 2026






