Pagination (Server-side)
Server-side pagination demo with a simulated backend API. Pagination state is managed explicitly in the component and sent to the backend on each change. This is the standard approach for backend integrations where the server handles the pagination logic. See the Pagination Guide for implementation details.
Username | Role | Account Status | Account Created On | Last Visited At | Visit Count |
|---|
{
"pagination": {
"pageIndex": 0,
"pageSize": 10
}
}
import {useMemo, useState} from "react"
import {useQuery} from "@tanstack/react-query"
import {
type ColumnDef,
getCoreRowModel,
type PaginationState,
} from "@qualcomm-ui/core/table"
import {Pagination} from "@qualcomm-ui/react/pagination"
import {ProgressRing} from "@qualcomm-ui/react/progress-ring"
import {
flexRender,
Table,
useReactTable,
useTablePagination,
} from "@qualcomm-ui/react/table"
import {CodeHighlight} from "@qualcomm-ui/react-mdx/code-highlight"
import {fetchData, type User} from "./use-data"
export function PaginationServerSideDemo() {
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
})
// always memoize your data and columns
const userColumns: ColumnDef<User>[] = useMemo(
() => [
{
accessorKey: "username",
header: "Username",
id: "username",
},
{
accessorKey: "role",
header: "Role",
id: "role",
size: 120,
},
{
accessorKey: "accountStatus",
header: "Account Status",
id: "accountStatus",
},
{
accessorKey: "createdAt",
header: "Account Created On",
id: "createdAt",
minSize: 205,
},
{
accessorKey: "lastVisitedAt",
header: "Last Visited At",
id: "lastVisitedAt",
minSize: 205,
},
{
accessorKey: "visitCount",
header: "Visit Count",
id: "visitCount",
},
],
[],
)
const {data, fetchStatus, isFetching} = useQuery({
placeholderData: (previousData) => previousData,
queryFn: () => fetchData(pagination),
queryKey: ["data", pagination],
})
const table = useReactTable({
columns: userColumns,
data: useMemo(() => data?.users ?? [], [data?.users]),
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
onPaginationChange: setPagination,
pageCount: data?.pageCount,
state: {
pagination,
},
})
const paginationProps = useTablePagination(table, {
totalCount: data?.totalUsers,
})
return (
<div className="flex w-full flex-col gap-4 p-2">
<Table.Root>
<Table.ActionBar>
<div className="text-neutral-primary font-body-sm flex items-center gap-1">
<span>Query:</span>
<span>{fetchStatus}</span>{" "}
{isFetching ? <ProgressRing className="ml-1" size="xs" /> : null}
</div>
</Table.ActionBar>
<Table.ScrollContainer>
<Table.Table>
<Table.Header>
{table.getHeaderGroups().map((headerGroup) => (
<Table.Row key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<Table.HeaderCell
key={header.id}
colSpan={header.colSpan}
style={{width: header.getSize()}}
>
{header.isPlaceholder ? null : (
<div>
{flexRender(
header.column.columnDef.header,
header.getContext(),
)}
</div>
)}
</Table.HeaderCell>
)
})}
</Table.Row>
))}
</Table.Header>
<Table.Body>
{table.getRowModel().rows.map((row) => {
return (
<Table.Row key={row.id}>
{row.getVisibleCells().map((cell) => {
return (
<Table.Cell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</Table.Cell>
)
})}
</Table.Row>
)
})}
</Table.Body>
</Table.Table>
</Table.ScrollContainer>
<Table.Pagination {...paginationProps}>
<Pagination.PageMetadata>
{({count, pageEnd, pageStart}) => (
<>
{!data?.pageCount ? (
<ProgressRing size="xs" />
) : (
`${pageStart}-${pageEnd} of ${count} results`
)}
</>
)}
</Pagination.PageMetadata>
<Pagination.PageButtons />
</Table.Pagination>
</Table.Root>
<CodeHighlight
className="w-fit"
code={JSON.stringify({pagination}, null, 2)}
disableCopy
language="json"
/>
</div>
)
}