DEV Community

RAMO
RAMO

Posted on

Running a Hebrew storefront in Next.js: the RTL bugs nobody warns you about

Our store at RAMO sells hardware, plumbing and garden supplies, and most of our customers read Hebrew. That means the whole storefront runs right-to-left. Setting dir="rtl" on the root element is the easy part. It flips the page, and for a day you think you're done.

Then the small bugs show up. None of them are hard, but nobody lists them in one place, so here's ours.

1. Stop writing left and right in CSS

The first round of bugs was always the same: a margin on the wrong side, an icon hugging the wrong edge, a dropdown opening off-screen. Every one came from margin-left, padding-right, left: 0 and friends.

The fix is to use logical properties everywhere:

/* before */
.price-tag { margin-left: 8px; text-align: left; }

/* after */
.price-tag { margin-inline-start: 8px; text-align: start; }
Enter fullscreen mode Exit fullscreen mode

inline-start means "the side where text begins", so it follows the direction automatically. If you use Tailwind, the ms-*, me-*, ps-*, pe-*, start-* and end-* utilities do the same thing. A lint rule that flags the physical versions is worth adding, so they don't creep back in.

2. Numbers, SKUs and model names inside Hebrew text

A product title like "ברז מטבח 3/4 דגם X-200" is a mix of Hebrew and Latin characters plus digits and slashes. The Unicode bidi algorithm handles most of it, but punctuation at the edges of a mixed run can jump to the wrong side. A trailing ) or a dash before a model number are the usual suspects.

Two things help:

  • Wrap anything that's "code-like" (SKUs, model numbers, dimensions) in <bdi> or a span with unicode-bidi: isolate. It keeps that chunk from being reordered with its neighbours.
  • For fields that are always Latin, like a SKU input, set dir="ltr" on that element alone.
<p className="title">
  {product.nameHe} <bdi>{product.model}</bdi>
</p>
Enter fullscreen mode Exit fullscreen mode

3. Prices

Show prices with Intl.NumberFormat('he-IL', { style: 'currency', currency: 'ILS' }) rather than gluing a ₪ sign onto a number by hand. Hand-built strings put the symbol on whatever side the developer happened to think of, and it looks wrong to someone who reads Hebrew every day.

One more thing: never let the price split across lines. A white-space: nowrap on the price element saves you from a shekel sign sitting alone on the next line on narrow phones.

4. Icons that point somewhere

Arrows, chevrons, "next" and "back" icons, and the little carousel controls all need to flip. A magnifying glass, a cart or a phone icon should not. The simplest approach is to tag directional icons explicitly:

[dir="rtl"] .icon-directional { transform: scaleX(-1); }
Enter fullscreen mode Exit fullscreen mode

It sounds trivial, but a "next" arrow pointing backwards in a checkout flow is the kind of thing that makes people hesitate.

5. Carousels and horizontal scroll

Horizontal scrolling in RTL is where browsers have historically disagreed most about scrollLeft values. If you write your own carousel, test it in Safari and Chrome both, and prefer scrollIntoView or scrollBy with logical thinking over raw scrollLeft math. A lot of slider libraries have an rtl option; turn it on rather than fighting it.

6. Mixed-direction pages

Some pages carry both directions: an English product spec sheet embedded in a Hebrew page, or a brand name in Latin letters. Put dir="auto" on user-generated or imported text blocks, like reviews or descriptions pulled from a supplier. The browser then picks the direction from the first strong character, which is right far more often than a hardcoded guess.

7. Test it with real content

Lorem ipsum hides every one of these bugs. Test RTL layouts with real product titles from the catalog, the long ugly ones with model numbers and fractions in them, like the ones you find in our pipe fittings category. If a layout survives those, it survives anything.

The short version

  • Logical CSS properties only, enforced by lint.
  • Isolate SKUs, model numbers and dimensions with <bdi>.
  • Format prices with Intl, and keep them on one line.
  • Flip directional icons, leave the rest alone.
  • dir="auto" for text you don't control.
  • Test with your real, messy catalog data.

None of this is exotic. It's just the list I wish someone had handed me before the first round of "why is this icon on the wrong side" bug reports.

Top comments (0)