JSON tools
Paginate JSON Data in JavaScript: Slice a Stable Array
Build client-side pagination with explicit page bounds, empty-state handling and stable ordering, and know when server pagination is required.
Paginate the decoded array, not the JSON string
Parse JSON text before paginating its records. Slicing the original string cuts characters and can produce invalid JSON; slicing the decoded array selects whole elements. This article implements client-side pagination for a complete array already available in memory. An endpoint that returns only one server page needs a different loading contract.
Choose whether the visible page number begins at one and how an out-of-range request is handled. The function below uses one-based page numbers, rejects non-integer or nonpositive inputs and clamps an otherwise valid request to the last available page. It deliberately returns page one with zero pages for an empty collection, so the interface has a stable position and can disable both navigation buttons.
function paginate(items, requestedPage, pageSize) {
if (!Array.isArray(items)) throw new TypeError("Expected an array");
if (!Number.isSafeInteger(requestedPage) || requestedPage < 1 ||
!Number.isSafeInteger(pageSize) || pageSize < 1) {
throw new RangeError("Use positive integer page and size");
}
const totalPages = Math.ceil(items.length / pageSize);
const page = Math.min(requestedPage, Math.max(1, totalPages));
const start = (page - 1) * pageSize;
return {
page, totalPages, totalItems: items.length,
items: items.slice(start, start + pageSize),
hasPrevious: page > 1,
hasNext: page < totalPages
};
}
Check the first, middle and last page
With five records identified as A, B, C, D and E and a page size of two, page one contains A and B, page two contains C and D, and page three contains E. Requesting page nine returns page three under this function's documented clamping rule. A different application might reject that request; the important point is to make the rule explicit and test it.
The slice reference explains the inclusive start and exclusive end positions. Slice creates a new array but does not deep-clone its objects. Editing a returned object's label can therefore affect the same object stored in the original collection. Use immutable updates or a deliberate copy strategy if the interface needs an isolated editing draft.
Filter and sort before selecting a page
Apply the active filter to the complete collection, establish its ordering, and then call paginate. Filtering only the currently visible page can incorrectly display an empty result even when matching records exist elsewhere. Compute totalItems and totalPages from the filtered collection so the counts describe what the user can browse.
Reset the requested page when a new query materially changes the collection, or accept the function's clamped result and update the visible page control to match it. Do not leave the control displaying page nine while rendering the records for page three.
Keep keyboard focus on a usable navigation control after updating the list, and announce the resulting page or item range through an appropriate status message. Disable unavailable directions using their actual control state so a keyboard user does not repeatedly activate a button that cannot change the page.
For stable navigation, choose a deterministic ordering with a tie-breaker when the main sort field is duplicated. If several records share the same label, a unique identifier can distinguish their order. Record insertions and deletions can still move records between client-side pages; pagination is a view over the current collection, not a permanent location assigned to each record.
Recognize the boundary of client-side pagination
This function does not reduce the amount of data fetched or parsed. If the full collection is too large, use an API that supports server pagination and follow its page or cursor contract. Do not infer a global total from the length of one returned server page unless the service explicitly defines that meaning.
The JavaScript JSON Parser can help inspect a small pasted JSON response for syntax. It does not execute this pagination function or request subsequent pages. Test the published function in the application runtime with empty data, exact page-size multiples, a final partial page and invalid page inputs before connecting navigation controls to it.


