I Built an ESLint Plugin to Stop RTL Layout Bugs
I Built an ESLint Plugin to Stop RTL Layout Bugs
About 400 million people read Arabic, Persian, or Urdu. Most of the web wasn't built for them.
In broken RTL layouts; text gets cut off. Icons face the wrong direction. Spacing looks weird because the whole page flipped and nobody noticed until someone sends a screenshot.
Tailwind actually has a fix for this. Has for a while.

Why Nobody Uses It
Tailwind has these "logical property" classes: ms-4 instead of ml-4, pe-2 instead of pr-2, text-start instead of text-left. They think in terms of before and after instead of left and right.
Set dir="rtl" on your page and they just work. No overrides, no extra CSS.
But good luck getting anyone to write ms-4 by default. The tutorials say ml-4. Your fingers type ml-4. There's no guardrail stopping you, so you ship it, and it breaks in Arabic.
I got tired of relying on people remembering. So I automated the remembering.
What the Plugin Actually Does
It's an ESLint plugin. It reads your code like a spell-checker and yells when it sees patterns that'll break in RTL.
It catches two things:
Physical direction classes in Tailwind
ml-4, mr-2, pl-3, text-left, left-0, rounded-l-lg, border-l-2 — all of these assume left-to-right and fall apart in RTL.
The plugin flags each one with the fix:
ml-4 → ms-4 mr-2 → me-2 pl-3 → ps-3 pr-1 → pe-1 text-left → text-start left-0 → start-0 rounded-l-lg → rounded-s-lg border-l-2 → border-s-2
Physical properties in CSS-in-JS
Same problem if you write styles as objects:
// This breaks in RTL const styles = { marginLeft: "1rem", paddingRight: "2rem" }; // This doesn't const styles = { marginInlineStart: "1rem", paddingInlineEnd: "2rem" };
Both checks are auto-fixable. Run eslint --fix and it rewrites everything.
The Logic Behind It
"Put space on the left" assumes everyone reads left-to-right. "Put space before the element" lets the browser figure out what "before" means based on the language.
Flexbox and Grid already do this — flip to RTL and items reorder themselves. Logical properties just bring that same behavior to spacing, borders, and text alignment.
Understanding this is easy. Going through your entire codebase and manually swapping every ml-* with ms-* is miserable work. Boring, error-prone, and nobody's paying you extra to do it.
That's why I made the plugin do it.
Setting It Up
npm install --save-dev eslint eslint-plugin-tailwind-rtl
Then in your ESLint config:
import tailwindRtl from "eslint-plugin-tailwind-rtl"; export default [tailwindRtl.configs.recommended];
Done. That's three lines, and now your project catches RTL bugs before they ship.
If you want to be strict about it — block PRs that introduce physical classes — bump the rule to an error:
import tailwindRtl from "eslint-plugin-tailwind-rtl"; export default [ tailwindRtl.configs.recommended, { rules: { "tailwind-rtl/tailwind/no-physical-classes": "error", }, }, ];
There's also a recommended-tailwind preset if you don't use CSS-in-JS. Only enables the Tailwind check.
Should You Use It?
Honestly, if your site might ever need to support another language, yes.
- Building a component library? Catch this upstream so nobody downstream gets a broken layout
- Supporting Arabic, or Persian? Prevents the "oh right, the Arabic version" panic
- Just trying to write better CSS? Logical properties are where CSS is heading anyway. Get used to them now and save yourself work later
It's free, open source (MIT), on npm. If you find an edge case I missed, send a PR.
What's Next
The plugin catches mistakes after they're written. I'm also writing a guide for AI coding tools — OpenCode, Cursor, Claude Code, etc. — that teaches them to write RTL-safe CSS from the start. Same rules, but aimed at code generation instead of cleanup.
If the thing writing your code already knows about logical properties, you never have a mess to clean up.