DEV Community

Rishabh Sethia
Rishabh Sethia

Posted on Originally published at innovatrixinfotech.com

How to Build an Arabic RTL Shopify Store: The Complete Technical Guide

There's a post I kept wishing existed when we first took on an Arabic Shopify build. A post that covered the real implementation: not just "add dir=rtl to your HTML" (which breaks more than it fixes), but the actual CSS overrides, the font stack decisions, the Liquid conditionals, and the third-party apps that silently wreck your layout the moment a customer switches to Arabic.

This is that post.

As a Shopify Partner that's built RTL stores for clients across Saudi Arabia and the UAE, we've made every mistake this guide warns you about. Consider this the distilled version.

What You'll Learn

  • How Shopify OS 2.0 handles RTL natively (and where it falls short)
  • The CSS properties that require manual overrides in RTL
  • Arabic font stacks that actually render well at small screen sizes
  • Using Liquid's locale.direction for conditional rendering
  • Handling bidirectional (bidi) content: Arabic text with embedded English numbers
  • Which popular Shopify apps break in RTL and how to fix them

Prerequisites

  • A Shopify store on a 2.0 theme (Dawn, Sense, Refresh, or a premium 2.0-compatible theme)
  • Access to Online Store > Themes > Edit Code
  • Arabic added as a language via Settings > Languages
  • Basic CSS knowledge

Step 1: Enable Arabic as a Language in Shopify

Before any code changes, add Arabic through Shopify's language system.

  1. Go to Settings > Languages
  2. Click Add language and select Arabic (ar)
  3. Use Shopify's Translate & Adapt app (free, from Shopify) to translate your theme strings, or use a third-party translation app
  4. Once Arabic is active, Shopify OS 2.0 themes with dir="rtl" support will automatically flip to RTL layout when a customer's locale is Arabic

What Shopify handles automatically in OS 2.0:

  • Text direction (dir="rtl" applied to <html>)
  • Text alignment for paragraph content
  • Some Flexbox reversals

What it does NOT handle automatically (you must fix these manually):

  • CSS left/right positioning on absolutely or fixed positioned elements
  • float declarations (largely legacy but still common in older themes/apps)
  • margin-left / margin-right asymmetric values
  • Icon direction (arrows, chevrons that point left in LTR should point right in RTL)
  • Third-party app widgets injected via JavaScript

Step 2: The Core CSS Overrides

Create a new snippet file called rtl-overrides.css.liquid and include it conditionally. Then add your RTL styles inside a conditional block.

In your theme.liquid (inside the <head> tag), add:

{% if locale.direction == 'rtl' %}
  {{ 'rtl-overrides.css' | asset_url | stylesheet_tag }}
{% endif %}
Enter fullscreen mode Exit fullscreen mode

In your assets/rtl-overrides.css file:

/* =============================================
   INNOVATRIX RTL OVERRIDES: Arabic Shopify Stores
   ============================================= */

/* Flip all left/right margin/padding pairs */
[dir="rtl"] .left-content { margin-left: 0; margin-right: var(--spacing); }
[dir="rtl"] .right-content { margin-right: 0; margin-left: var(--spacing); }

/* Flip Flexbox row direction */
[dir="rtl"] .flex-row { flex-direction: row-reverse; }

/* Product grid: image + content alignment */
[dir="rtl"] .product-card__info { text-align: right; }
[dir="rtl"] .product-card__price { text-align: right; }

/* Navigation: reverse the dropdown direction */
[dir="rtl"] .header__menu-item .header__submenu { 
  left: auto; 
  right: 0; 
}

/* Chevron/arrow icons: flip horizontally */
[dir="rtl"] .icon-arrow-right,
[dir="rtl"] .icon-chevron-right {
  transform: scaleX(-1);
}

/* Breadcrumb separator */
[dir="rtl"] .breadcrumb__separator { transform: scaleX(-1); }

/* Input fields: right-align text */
[dir="rtl"] input,
[dir="rtl"] textarea,
[dir="rtl"] select {
  text-align: right;
  direction: rtl;
}

/* Cart quantity: fix mis-aligned stepper */
[dir="rtl"] .quantity-selector {
  flex-direction: row-reverse;
}
Enter fullscreen mode Exit fullscreen mode

Critical gotcha: Don't use [dir="rtl"] * { direction: rtl; } as a catch-all. It will break embedded iframes (payment widgets, review apps, chat tools) that need to render LTR internally. Target elements explicitly.


Step 3: Arabic Font Stack

Shopify themes ship with Latin fonts by default. Arabic text rendered in a Latin font falls back to the browser's default Arabic font, which is usually inconsistent across devices and rarely legible at small sizes.

The three Arabic Google Fonts that perform well in ecommerce contexts:

  • Cairo: clean, geometric, excellent readability at all sizes, works at 14px+
  • Tajawal: slightly more rounded, good for headings and hero text
  • Noto Sans Arabic: extremely legible at small sizes, ideal for body copy and meta

Add to the <head> in theme.liquid:

{% if locale.direction == 'rtl' %}
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;500;600;700&family=Tajawal:wght@400;500;700&display=swap" rel="stylesheet">
{% endif %}
Enter fullscreen mode Exit fullscreen mode

In your rtl-overrides.css:

/* Apply Arabic font stack when RTL is active */
[dir="rtl"] body,
[dir="rtl"] p,
[dir="rtl"] .product-card__title,
[dir="rtl"] .cart__item-name {
  font-family: 'Cairo', 'Tajawal', 'Noto Sans Arabic', Arial, sans-serif;
  line-height: 1.7; /* Arabic text needs more line height than Latin */
  font-size: 1.05rem; /* Slight upsize: Arabic at 14px is harder to read */
}

[dir="rtl"] h1,
[dir="rtl"] h2,
[dir="rtl"] h3 {
  font-family: 'Tajawal', 'Cairo', sans-serif;
  font-weight: 700;
  letter-spacing: 0; /* Zero letter-spacing: Arabic glyphs connect */
}
Enter fullscreen mode Exit fullscreen mode

Important: Arabic is a cursive script: glyphs connect to each other. Never apply letter-spacing values to Arabic text. It breaks the visual joining of characters and looks like corrupted text.


Step 4: Liquid Conditional Rendering

Some layout decisions require Liquid logic, not just CSS. The locale.direction variable returns "rtl" or "ltr" based on the active language.

Example: Conditional icon rendering

{% if locale.direction == 'rtl' %}
  {% render 'icon-arrow-left' %}
{% else %}
  {% render 'icon-arrow-right' %}
{% endif %}
Enter fullscreen mode Exit fullscreen mode

Example: RTL-aware product card layout

<div class="product-card {% if locale.direction == 'rtl' %}product-card--rtl{% endif %}">
  <div class="product-card__image">...</div>
  <div class="product-card__info">
    <h3 class="product-card__title">{{ product.title }}</h3>
    <p class="product-card__price">{{ product.price | money }}</p>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Example: RTL-aware <html> tag (add to theme.liquid)

<html lang="{{ request.locale.iso_code }}" dir="{{ locale.direction }}">
Enter fullscreen mode Exit fullscreen mode

This ensures the dir attribute is dynamically set on the document root based on the active language: which is what drives all CSS [dir="rtl"] selectors.


Step 5: Handling Bidirectional (Bidi) Content

Mixed Arabic/English content is common in ecommerce: product names in Arabic, prices in Arabic numerals or English numerals, brand names in Latin characters embedded in Arabic descriptions.

The Unicode bidirectional algorithm handles most of this automatically, but it can produce unexpected results in specific cases: especially around punctuation, numbers at the end of Arabic strings, and parentheses.

Use the unicode-bidi CSS property for mixed-direction containers:

[dir="rtl"] .product-description {
  unicode-bidi: plaintext;
  /* Renders bidi content in its natural direction without forcing the container direction */
}
Enter fullscreen mode Exit fullscreen mode

For product names with embedded English brand names:

<span dir="auto">{{ product.title }}</span>
Enter fullscreen mode Exit fullscreen mode

The dir="auto" HTML attribute uses the first strong character in the text to set direction: if the product name starts with Arabic, it renders RTL; if it starts with a Latin brand name, it renders LTR. This is more reliable than hard-coding for mixed catalogs.


Step 6: Third-Party Apps That Break in RTL

This is the section you won't find in most guides. Here are the apps and widget categories that commonly produce broken layouts in Arabic RTL Shopify stores, and how to handle each:

Review Apps (Judge.me, Loox, Stamped.io)
Stars-and-review widgets inject their own CSS, often with hard-coded text-align: left and float: left. Override via the Shopify theme's custom CSS:

[dir="rtl"] .jdgm-rev__body,
[dir="rtl"] .jdgm-rev__author {
  text-align: right;
  direction: rtl;
}
Enter fullscreen mode Exit fullscreen mode

BNPL Widgets (Tabby, Tamara)
Tabby and Tamara both have Arabic-aware widget options: pass lang="ar" in their embed configuration to get Arabic-localised messaging. Without this, they default to English.

Klaviyo / Email Capture Popups
Klaviyo's popup form renders LTR by default. In Klaviyo's form editor, set text direction to RTL in the form settings for Arabic templates.

Live Chat (Tidio, Freshchat, Intercom)
Most live chat tools auto-detect the user's browser language and flip their own widget. If yours doesn't, check the language configuration in the chat tool's settings: most enterprise-tier chat tools have explicit RTL support.

Search Apps (Searchie, Boost Commerce)
Search result dropdowns and filter panels often have their own CSS scope. You'll need app-specific overrides. Test your search experience in Arabic explicitly: it's commonly broken and commonly overlooked.


Common Issues and Fixes

Problem: Checkout page is still LTR in Arabic mode.
Fix: Shopify's checkout (for non-Shopify Plus merchants) is a Shopify-controlled surface. You cannot customise its RTL behaviour without a Shopify Plus checkout.liquid. For standard plans, the checkout will use Shopify's built-in Arabic support, which is reasonable but not fully customisable.

Problem: Product image gallery carousel swiping direction is inverted (swipe left in Arabic, but it goes right).
Fix: Most carousel libraries (Splide, Swiper) have a dir option. Set dir: 'rtl' in your carousel initialisation when locale.direction == 'rtl'.

Problem: Breadcrumb shows Home / Products / Product Name instead of اسم المنتج / المنتجات / الرئيسية.
Fix: This is a translation issue, not an RTL issue. Use Translate & Adapt to translate breadcrumb strings. The RTL layout will handle direction once translation is in place.

Problem: Email notifications are still LTR.
Fix: Shopify email notification templates are separate from theme files. Go to Settings > Notifications and manually add dir="rtl" to the relevant email HTML templates for Arabic-language notifications.


Results: What Proper RTL Delivers

For one of our Saudi Arabia-facing clients, we implemented the full RTL treatment described above on a mid-size fashion store. The before/after on the Arabic-language variant told the story clearly: session duration in Arabic increased substantially, and cart abandonment on the Arabic checkout path dropped to match the English path: which it had meaningfully underperformed before the RTL work.

Proper RTL is not cosmetic. Saudi and UAE consumers who encounter a broken Arabic layout typically don't report it. They leave. The conversion gap between a properly-built Arabic store and a half-implemented one is measurable in direct revenue.

If you want us to audit your existing Shopify store's Arabic experience or build a new RTL-ready store, start with a discovery call here.


Frequently Asked Questions

Does Shopify natively support Arabic RTL?
Partially. Shopify OS 2.0 themes apply dir="rtl" to the HTML element when Arabic is the active language, and handle basic text direction. However, CSS positioning, flexbox layouts, icon direction, margins, and third-party app widgets all require manual fixes. Native support handles perhaps 60-70% of what a proper Arabic store needs.

Can I build a bilingual English/Arabic store on Shopify?
Yes. Using Shopify Markets with multiple languages, you can serve English (LTR) and Arabic (RTL) from the same store. The locale.direction variable handles layout switching automatically. Translation is handled via Translate & Adapt or a paid app like Weglot.

What Shopify plan do I need for a bilingual store?
Multiple languages are available on all Shopify plans. You can add up to 20 languages on standard plans. Shopify Markets (which lets you configure currency, language, and domains per region) is available from Basic and above.

Which Arabic fonts work best in Shopify?
For body copy: Noto Sans Arabic (most legible at small sizes). For headings: Tajawal or Cairo. Always use line-height: 1.6 to 1.8 for Arabic body text: Arabic scripts need more vertical space than Latin equivalents. Never use letter-spacing on Arabic text.

How do I handle product names that are in English inside an Arabic store?
Use dir="auto" on the element containing the product name. This uses the first strong-directional character to set the display direction automatically: works well for mixed-language product catalogs.

Does this guide work for Shopify Hydrogen (headless) stores?
The Liquid-specific parts don't apply to headless builds, but the CSS principles, font strategy, and bidi content handling are all relevant. In Hydrogen, use React's dir prop on the root element and manage RTL through Tailwind's RTL plugin or a CSS-in-JS RTL helper.

What's the hardest part of building an Arabic Shopify store?
In our experience: third-party app compatibility. The core theme can be handled cleanly with the approach above. The unpredictable part is the 10-15 apps a typical merchant has installed, each injecting their own CSS that may fight your RTL overrides. Audit every installed app in Arabic view before launch.


Originally published at Innovatrix Infotech

Top comments (0)