Sorting & pagination

MonkeyTab can sort and paginate data two ways: client-side (the component does it internally) and server-side (you control it via props and fetch from your backend).


Sorting

Client-side (default)

Click a column header to sort. No props needed — MonkeyTab sorts the rows array in memory.

Server-side (controlled)

Pass sortBy, sortDirection, and onSortChange to hand sorting control to your backend:

const [sortBy,  setSortBy]  = useState<string | null>(null);
const [sortDir, setSortDir] = useState<'asc' | 'desc' | null>(null);

// Your data fetch, re-runs when sort changes
const { data } = useQuery(['rows', sortBy, sortDir], () =>
  api.getRows({ sort: sortBy, dir: sortDir })
);

<MonkeyTable
  columns={columns}
  rows={data}
  sortBy={sortBy}
  sortDirection={sortDir}
  onSortChange={(field, dir) => {
    setSortBy(field);
    setSortDir(dir);
  }}
/>

When sortBy is set, clicking a header calls onSortChange instead of sorting in memory. The column header shows the sort indicator.

Type-aware sort labels

Sort menu labels adapt to the column type:

Type Ascending label Descending label
Text A → Z Z → A
Number 0 → 9 9 → 0
Date Oldest first Newest first
Boolean False first True first
Rating Low → High High → Low

Filtering

The filter panel (toolbar → filter button) lets users build type-aware filter conditions.

Client-side (default)

Filters run on the rows array in memory. Nothing to configure.

Server-side

To apply filters on the server, read the current filter state from the onFilterChange callback (if you've wired it up) or listen for onCellChange/etc. For now, the most common pattern for server-side filtering is to add filter controls outside the grid and pass a pre-filtered rows prop.


Pagination

Client-side (default)

When totalRows is not set, the grid renders all rows from the rows array. Use pageSize to limit how many are shown:

// No pagination props — renders all rows
<MonkeyTable columns={columns} rows={rows} />

Server-side pagination

Set totalRows to enable pagination controls. Manage page yourself:

const [page, setPage] = useState(1);
const pageSize = 100;

const { data, totalCount, isLoading } = useQuery(
  ['rows', page],
  () => api.getRows({ page, limit: pageSize })
);

<MonkeyTable
  columns={columns}
  rows={data ?? []}
  totalRows={totalCount}
  page={page}
  pageSize={pageSize}
  onPageChange={(p) => setPage(p)}
  paginationMode="simple"
  paginationLoading={isLoading}
/>

Pagination modes

Mode UI
'simple' (default) Previous / Next buttons with "Showing X–Y of Z"
'load-more' A single "Load more" button that appends rows
<MonkeyTable
  paginationMode="load-more"
  ...
/>

Combining sort + filter + pagination

When doing everything server-side, wire all three together and reset page to 1 on sort or filter changes:

const [page,    setPage]    = useState(1);
const [sortBy,  setSortBy]  = useState<string | null>(null);
const [sortDir, setSortDir] = useState<'asc' | 'desc' | null>(null);

const { data, total, isLoading } = useQuery(
  ['rows', page, sortBy, sortDir],
  () => api.getRows({ page, limit: 50, sort: sortBy, dir: sortDir })
);

<MonkeyTable
  columns={columns}
  rows={data ?? []}

  // Pagination
  totalRows={total}
  page={page}
  pageSize={50}
  onPageChange={setPage}
  paginationLoading={isLoading}

  // Sorting
  sortBy={sortBy}
  sortDirection={sortDir}
  onSortChange={(field, dir) => {
    setSortBy(field);
    setSortDir(dir);
    setPage(1);   // reset to first page on sort change
  }}
/>

Ghost grid

When height is a fixed pixel value, empty space below the last row looks blank. The ghost grid fills that space with faint placeholder rows and columns — it's on by default for fixed-height tables.

// Auto-on when height is a number
<MonkeyTable height={500} ... />

// Explicit: choose how many ghost rows/columns
<MonkeyTable height={500} ghostGrid={{ rows: 8, columns: 3 }} ... />

// Turn off
<MonkeyTable height={500} ghostGrid={false} ... />

Ghost column headers create a real column when clicked; ghost row cells create a new row (when editable and allowCreateRecord are true).


Height modes

Value Behavior
'auto' Fits content — height grows with rows, no scrollbar for small tables
number (px) Fixed height — vertical scrolling when rows overflow
CSS string ('100%', '50vh') Fills a parent element

Pair height="auto" with maxHeight to cap growth:

<MonkeyTable height="auto" maxHeight={600} ... />