Skip to content

[Svelte] Client-side paginatedRowModel doesn't recompute when pagination state is externally controlled via state.pagination + onPaginationChange #6374

Closed

Description

@frenandre

TanStack Table version

v9.0.0-beta.29

Framework/Library version

@sveltejs/kit 2.69.1

Describe the bug and the steps to reproduce it

Describe the bug

When pagination state is externally controlled (v8-style state.pagination + onPaginationChange, or the new createTableState helper), table.getState().pagination.pageIndex updates correctly, but table.getRowModel().rows never reflects the new page — it always shows the rows from pageIndex: 0.

The identical pattern works correctly for sorting (state.sorting + onSortingChange), so this appears isolated to paginatedRowModel specifically.

Using manualPagination: true (server-side pagination, no client-side paginatedRowModel slicing) works correctly — the bug only affects client-side pagination.

Your minimal, reproducible example

<script lang="ts">
  import {
    createTable,
    createTableState,
    tableFeatures,
    rowPaginationFeature,
    createPaginatedRowModel,
    type PaginationState,
  } from '@tanstack/svelte-table'

  const features = tableFeatures({
    rowPaginationFeature,
    paginatedRowModel: createPaginatedRowModel(),
  })

  const [pagination, setPagination] = createTableState<PaginationState>({
    pageIndex: 0,
    pageSize: 15,
  })

  let list = $state(/* e.g. 250 rows */)

  const table = createTable({
    features,
    columns,
    get data() {
      return list
    },
    state: {
      get pagination() {
        return pagination()
      },
    },
    onPaginationChange: (updater) => {
      setPagination(updater) // <-- presence of this alone breaks getRowModel()
    },
  })
</script>

<!-- table.nextPage() correctly updates table.getState().pagination.pageIndex to 1,
     but table.getRowModel().rows still shows the same 15 rows as page 0 -->
<button onclick={() => table.nextPage()}>Next</button>

Steps to reproduce

  1. Create a table with rowPaginationFeature + createPaginatedRowModel(), more data than fits on one page (e.g. 250 rows, pageSize: 15).
  2. Control pagination externally via state.pagination + onPaginationChange (tested both with a raw Svelte $state object and with createTableState).
  3. Click "next page" (table.nextPage() or table.setPageIndex(n)).
  4. Observe table.getState().pagination.pageIndex — it updates correctly.
  5. Observe table.getRowModel().rows — it does not change; the same rows from page 0 keep being returned.

Expected behavior

table.getRowModel().rows should reflect the current pageIndex/pageSize, the same way it does when the table manages pagination internally (no state.pagination/onPaginationChange provided) or the same way sortedRowModel reacts to externally-controlled sorting.

How often does this bug happen?

Every time, 100% reproducible.

Platform

  • Version of TanStack Table: 9.0.0-beta.29
  • Framework: Svelte 5 (Runes mode)

Additional context

  • Confirmed this is not a $state/proxy-identity issue on the app side: tested both a raw let pagination = $state({...}) and createTableState<PaginationState>(...), identical behavior in both cases.
  • The identical pattern (state.sorting + onSortingChange) works correctly, so this seems isolated to the pagination row model's memoization/dependency tracking specifically.
  • The equivalent v8 configuration (state.pagination + onPaginationChange, getPaginationRowModel: getPaginationRowModel()) works correctly — this is a regression relative to v8 behavior.
  • Workaround currently in use: let the table manage pagination state fully internally (no state.pagination/onPaginationChange), and observe page changes passively via an effect on table.getState().pagination.pageIndex to drive side effects (e.g. resetting a selected-row index).

Your Minimal, Reproducible Example - (Sandbox Highly Recommended)


Screenshots or Videos (Optional)

No response

Do you intend to try to help solve this bug with your own PR?

None

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Activity

  1. frenandre commented on Jul 3, 2026

    @frenandre
    Author

    Update: I've narrowed this down further and it turns out this is not a library bug — it was a reactivity mismatch in my own code between the Svelte primitive used for the data source and the manualPagination mode. Apologies for the noise.

    Root cause: the reactivity primitive backing the data getter needs to match manualPagination:

    manualPagination: false (client-side pagination) → data source must be $state:

    let list = $state(data.list.content)
    
    const table = createTable({
      columns,
      get data() { return list },
      manualPagination: false,
      // ...
    })

    manualPagination: true (server-side pagination) → data source must be $derived:

    let list = $derived(data.list.content)
    
    const table = createTable({
      columns,
      get data() { return list },
      manualPagination: true,
      // ...
    })

    With the correct combination, state.pagination + onPaginationChange (externally controlled, no workaround needed) works correctly in both modes — table.getRowModel().rows updates as expected on page change.

    The mismatched combination ($state + manualPagination: true, or $derived + manualPagination: false) is what caused the symptom I originally reported (pageIndex updates, getRowModel().rows doesn't).

    I'd still guess there's something worth looking at here — ideally either primitive should work regardless of manualPagination, so if there's a reason the adapter's dependency tracking distinguishes between $state and $derived sources depending on the mode, it might be worth a note in the docs (I didn't see this documented anywhere) or a fix so both are supported uniformly. But this is no longer the sharp reproducible library bug I described — closing this out / leaving it to maintainer discretion whether to keep open as a docs/DX issue or close.

    Thanks for the library either way, and sorry again for the initial misdiagnosis!

  2. frenandre commented on Jul 5, 2026

    @frenandre
    Author

    Final update: found the actual root cause — this was autoResetPageIndex (defaults to true when manualPagination is false) resetting pageIndex back to 0 immediately after each page change. Setting autoResetPageIndex: false resolved it completely. Not a library bug — closing this out, sorry for the back-and-forth!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions