Skip to main content

Overview

React Data Grid supports right-to-left (RTL) languages like Arabic, Hebrew, Persian, and Urdu. The grid automatically adapts its layout and behavior for RTL text direction.

Enabling RTL

Set the direction prop to 'rtl':
import { DataGrid } from 'react-data-grid';

function MyGrid() {
  return <DataGrid columns={columns} rows={rows} direction="rtl" />;
}
The default direction is 'ltr' (left-to-right).

RTL Behavior

When direction="rtl" is set, the following changes occur:

Column Flow

Columns flow from right to left:
const columns: readonly Column<Row>[] = [
  { key: 'id', name: 'معرف' }, // Rightmost column
  { key: 'name', name: 'الاسم' },
  { key: 'email', name: 'البريد الإلكتروني' } // Leftmost column
];

<DataGrid columns={columns} rows={rows} direction="rtl" />;

Frozen Columns

Frozen columns are pinned on the right side:
const columns: readonly Column<Row>[] = [
  {
    key: 'id',
    name: 'معرف',
    frozen: true // Pinned to the right in RTL
  },
  { key: 'name', name: 'الاسم' },
  { key: 'email', name: 'البريد الإلكتروني' }
];

<DataGrid columns={columns} rows={rows} direction="rtl" />;
In LTR mode, frozen columns are pinned on the left. In RTL mode, they’re pinned on the right.

Column Resize Handle

The resize handle appears on the left edge of columns (instead of right):
const columns: readonly Column<Row>[] = [
  {
    key: 'name',
    name: 'الاسم',
    resizable: true // Handle on left edge in RTL
  }
];

Scrollbar Position

The horizontal scrollbar is positioned on the left side:
<DataGrid columns={columns} rows={rows} direction="rtl" />

Keyboard Navigation

Arrow key navigation adapts to RTL:
  • Arrow Left → Moves to the cell on the right
  • Arrow Right → Moves to the cell on the left
import { DataGrid } from 'react-data-grid';

function MyGrid() {
  return (
    <DataGrid
      aria-label="قائمة المنتجات"
      columns={columns}
      rows={rows}
      direction="rtl"
    />
  );
}
The grid automatically handles left/right key mapping. You don’t need to modify onCellKeyDown handlers.

Dynamic Direction

Switch between LTR and RTL dynamically:
import { useState } from 'react';
import { DataGrid, type Direction } from 'react-data-grid';

function MyGrid() {
  const [direction, setDirection] = useState<Direction>('ltr');

  return (
    <>
      <button onClick={() => setDirection('ltr')}>LTR</button>
      <button onClick={() => setDirection('rtl')}>RTL</button>

      <DataGrid
        columns={columns}
        rows={rows}
        direction={direction}
      />
    </>
  );
}

Internationalization

Combine with i18n libraries:
import { useTranslation } from 'react-i18next';
import { DataGrid, type Column } from 'react-data-grid';

function MyGrid() {
  const { t, i18n } = useTranslation();
  const direction = i18n.dir(); // Returns 'ltr' or 'rtl'

  const columns: readonly Column<Row>[] = [
    { key: 'id', name: t('columns.id') },
    { key: 'name', name: t('columns.name') },
    { key: 'email', name: t('columns.email') }
  ];

  return (
    <DataGrid
      aria-label={t('grid.products')}
      columns={columns}
      rows={rows}
      direction={direction}
    />
  );
}

Example with react-i18next

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

i18n.use(initReactI18next).init({
  resources: {
    en: {
      translation: {
        'columns.id': 'ID',
        'columns.name': 'Name',
        'columns.email': 'Email'
      }
    },
    ar: {
      translation: {
        'columns.id': 'معرف',
        'columns.name': 'الاسم',
        'columns.email': 'البريد الإلكتروني'
      }
    }
  },
  lng: 'en',
  fallbackLng: 'en'
});

Document Direction

For full RTL support, set the document direction:
import { useEffect } from 'react';
import { DataGrid } from 'react-data-grid';

function MyApp() {
  const direction = 'rtl';

  useEffect(() => {
    document.documentElement.dir = direction;
    document.documentElement.lang = 'ar'; // Set language
  }, [direction]);

  return <DataGrid columns={columns} rows={rows} direction={direction} />;
}
Setting document.documentElement.dir affects the entire page. Only do this if your entire application is RTL.

CSS Considerations

Logical Properties

The grid uses CSS logical properties internally, which automatically adapt to text direction:
/* Instead of left/right */
margin-left: 10px;
margin-right: 5px;

/* Use inline-start/inline-end */
margin-inline-start: 10px;
margin-inline-end: 5px;

Custom Styles

When adding custom styles, use logical properties for RTL support:
import { DataGrid } from 'react-data-grid';

const columns: readonly Column<Row>[] = [
  {
    key: 'name',
    name: 'الاسم',
    renderCell({ row }) {
      return (
        <div
          style={{
            paddingInlineStart: '10px', // ✅ Adapts to RTL
            paddingInlineEnd: '5px',
            // paddingLeft: '10px', // ❌ Fixed direction
          }}
        >
          {row.name}
        </div>
      );
    }
  }
];
Use inline-start/inline-end instead of left/right for direction-aware layouts.

Common Patterns

Language Selector

import { useState } from 'react';
import { DataGrid, type Direction } from 'react-data-grid';

const languages = {
  en: { name: 'English', direction: 'ltr' as Direction },
  ar: { name: 'العربية', direction: 'rtl' as Direction },
  he: { name: 'עברית', direction: 'rtl' as Direction }
};

function MyGrid() {
  const [lang, setLang] = useState<keyof typeof languages>('en');
  const { direction } = languages[lang];

  return (
    <>
      <select value={lang} onChange={(e) => setLang(e.target.value as keyof typeof languages)}>
        {Object.entries(languages).map(([code, { name }]) => (
          <option key={code} value={code}>
            {name}
          </option>
        ))}
      </select>

      <DataGrid
        columns={getLocalizedColumns(lang)}
        rows={rows}
        direction={direction}
      />
    </>
  );
}

Detecting User Preference

import { useMemo } from 'react';
import { DataGrid, type Direction } from 'react-data-grid';

function MyGrid() {
  const direction = useMemo((): Direction => {
    const htmlDir = document.documentElement.dir;
    if (htmlDir === 'rtl') return 'rtl';

    // Detect from language
    const lang = navigator.language;
    const rtlLangs = ['ar', 'he', 'fa', 'ur'];
    if (rtlLangs.some((rtl) => lang.startsWith(rtl))) {
      return 'rtl';
    }

    return 'ltr';
  }, []);

  return <DataGrid columns={columns} rows={rows} direction={direction} />;
}

Testing RTL

Visual Testing

import { render, screen } from '@testing-library/react';
import { DataGrid } from 'react-data-grid';

test('renders in RTL mode', () => {
  render(
    <DataGrid
      aria-label="Products"
      columns={columns}
      rows={rows}
      direction="rtl"
    />
  );

  const grid = screen.getByRole('grid', { name: 'Products' });
  expect(grid).toHaveAttribute('dir', 'rtl');
});

Browser Testing

Test in different browsers:
// Set browser to RTL mode for manual testing
document.documentElement.dir = 'rtl';

Browser Support

RTL support works in all modern browsers:
  • Chrome 76+
  • Firefox 68+
  • Safari 12+
  • Edge 79+
The grid uses standard CSS logical properties with broad browser support.

Known Limitations

Currently, there are no known RTL limitations. The grid fully supports RTL layouts.

Best Practices

For RTL support:
  • Always set the direction prop
  • Use CSS logical properties in custom styles
  • Test with actual RTL content
  • Set document.documentElement.dir when appropriate
  • Provide localized column names and labels
Use browser DevTools to toggle dir="rtl" on the document element for quick RTL testing.

Example: Full RTL Implementation

import { useState, useEffect } from 'react';
import { DataGrid, type Column, type Direction } from 'react-data-grid';
import 'react-data-grid/lib/styles.css';

interface Row {
  id: number;
  name: string;
  email: string;
}

const columnsEn: readonly Column<Row>[] = [
  { key: 'id', name: 'ID', width: 80 },
  { key: 'name', name: 'Name', resizable: true },
  { key: 'email', name: 'Email', resizable: true }
];

const columnsAr: readonly Column<Row>[] = [
  { key: 'id', name: 'معرف', width: 80 },
  { key: 'name', name: 'الاسم', resizable: true },
  { key: 'email', name: 'البريد الإلكتروني', resizable: true }
];

function MyGrid() {
  const [language, setLanguage] = useState<'en' | 'ar'>('en');
  const direction: Direction = language === 'ar' ? 'rtl' : 'ltr';
  const columns = language === 'ar' ? columnsAr : columnsEn;

  useEffect(() => {
    document.documentElement.dir = direction;
    document.documentElement.lang = language;
  }, [direction, language]);

  const rows: Row[] = [
    { id: 1, name: 'أحمد محمد', email: '[email protected]' },
    { id: 2, name: 'فاطمة علي', email: '[email protected]' },
    { id: 3, name: 'محمد حسن', email: '[email protected]' }
  ];

  return (
    <div style={{ padding: '20px' }}>
      <button onClick={() => setLanguage('en')}>English</button>
      <button onClick={() => setLanguage('ar')}>العربية</button>

      <DataGrid
        aria-label={language === 'ar' ? 'قائمة المستخدمين' : 'User list'}
        columns={columns}
        rows={rows}
        direction={direction}
        style={{ height: '400px' }}
      />
    </div>
  );
}

export default MyGrid;

Build docs developers (and LLMs) love