Migration Guide

From Hardcoded Values to Config System

Earlier versions of the table components hardcoded configuration values such as debounce delays, page size options, and i18n helpers directly inside each component. The config system centralises these values so they can be changed in one place and automatically propagate to every table instance in the application.

Before

tsx
// Values were hardcoded inside each component
const DEBOUNCE_MS = 300;
const PAGE_SIZE_OPTIONS = [10, 20, 50, 100];

const { t } = useTranslations("table");
const isArabic = useIsArabic();

// Direction was derived manually
const direction = isArabic ? "rtl" : "ltr";

After

tsx
// Values come from the resolved config
const config = useTableConfig();

const debounceMs = config.search.debounceMs;
const pageSizeOptions = config.pagination.pageSizeOptions;

// Unified translation hook — no need for useTranslations("table") directly
const t = useTableTranslations();

// Direction is part of the config
const direction = config.i18n.direction;
No breaking changes. Without a TableProvider, all components automatically fall back to DEFAULT_TABLE_CONFIG, which contains the same values that were previously hardcoded as defaults. Existing usage continues to work without any modifications.

Adding TableProvider

Adopting TableProvider is incremental. The three stages below show how to introduce it without disrupting existing behaviour, then how to start applying overrides.

Stage 1 — Before (no provider):

tsx
// No provider — components use DEFAULT_TABLE_CONFIG
export default function App() {
  return (
    <main>
      <DataTable columns={columns} data={data} />
    </main>
  );
}

Stage 2 — After, same behaviour (empty config):

tsx
// TableProvider with no overrides — behaviour is identical to Stage 1
export default function App() {
  return (
    <TableProvider config={{}}>
      <main>
        <DataTable columns={columns} data={data} />
      </main>
    </TableProvider>
  );
}

Stage 3 — After, with overrides:

tsx
// TableProvider with a config override applied to all table instances
export default function App() {
  return (
    <TableProvider
      config={{
        pagination: {
          defaultPageSize: 25,
        },
      }}
    >
      <main>
        <DataTable columns={columns} data={data} />
      </main>
    </TableProvider>
  );
}
One TableProvider per application root is typically sufficient. Avoid nesting multiple providers unless different subtrees of the application genuinely require isolated config overrides.