diff --git a/COMPONENT_INDEX.md b/COMPONENT_INDEX.md
index f495d031..0d0c1429 100644
--- a/COMPONENT_INDEX.md
+++ b/COMPONENT_INDEX.md
@@ -2681,24 +2681,25 @@ None.
### Props
-| Prop name | Required | Kind | Reactive | Type | Default value | Description |
-| :-------------------- | :------- | :--------------- | :------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------ |
-| pageSize | No | let
| Yes | number
| 10
| Specify the number of items to display in a page |
-| page | No | let
| Yes | number
| 1
| Specify the current page index |
-| totalItems | No | let
| No | number
| 0
| Specify the total number of items |
-| disabled | No | let
| No | boolean
| false
| Set to `true` to disable the pagination |
-| forwardText | No | let
| No | string
| "Next page"
| Specify the forward button text |
-| backwardText | No | let
| No | string
| "Previous page"
| Specify the backward button text |
-| itemsPerPageText | No | let
| No | string
| "Items per page:"
| Specify the items per page text |
-| itemText | No | let
| No | (min: number, max: number) => string
| (min, max) => \`${min}–${max} item${max === 1 ? "" : "s"}\`
| Override the item text |
-| itemRangeText | No | let
| No | (min: number, max: number, total: number) => string
| (min, max, total) => \`${min}–${max} of ${total} item${max === 1 ? "" : "s"}\`
| Override the item range text |
-| pageInputDisabled | No | let
| No | boolean
| false
| Set to `true` to disable the page input |
-| pageSizeInputDisabled | No | let
| No | boolean
| false
| Set to `true` to disable the page size input |
-| pageSizes | No | let
| No | ReadonlyArray
| [10]
| Specify the available page sizes |
-| pagesUnknown | No | let
| No | boolean
| false
| Set to `true` if the number of pages is unknown |
-| pageText | No | let
| No | (page: number) => string
| (page) => \`page ${page}\`
| Override the page text |
-| pageRangeText | No | let
| No | (current: number, total: number) => string
| (current, total) => \`of ${total} page${total === 1 ? "" : "s"}\`
| Override the page range text |
-| id | No | let
| No | string
| "ccs-" + Math.random().toString(36)
| Set an id for the top-level element |
+| Prop name | Required | Kind | Reactive | Type | Default value | Description |
+| :-------------------- | :------- | :--------------- | :------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| pageSize | No | let
| Yes | number
| 10
| Specify the number of items to display in a page |
+| page | No | let
| Yes | number
| 1
| Specify the current page index |
+| totalItems | No | let
| No | number
| 0
| Specify the total number of items |
+| pageWindow | No | let
| No | number
| 1000
| If `totalItems` is a large number, it can affect the
rendering performance of this component since its value
is used to calculate the number of pages in the native
select dropdown. This value creates a small window of
pages rendered around the current page. By default,
a maximum of 1000 select items are rendered. |
+| disabled | No | let
| No | boolean
| false
| Set to `true` to disable the pagination |
+| forwardText | No | let
| No | string
| "Next page"
| Specify the forward button text |
+| backwardText | No | let
| No | string
| "Previous page"
| Specify the backward button text |
+| itemsPerPageText | No | let
| No | string
| "Items per page:"
| Specify the items per page text |
+| itemText | No | let
| No | (min: number, max: number) => string
| (min, max) => \`${min}–${max} item${max === 1 ? "" : "s"}\`
| Override the item text |
+| itemRangeText | No | let
| No | (min: number, max: number, total: number) => string
| (min, max, total) => \`${min}–${max} of ${total} item${max === 1 ? "" : "s"}\`
| Override the item range text |
+| pageInputDisabled | No | let
| No | boolean
| false
| Set to `true` to disable the page input |
+| pageSizeInputDisabled | No | let
| No | boolean
| false
| Set to `true` to disable the page size input |
+| pageSizes | No | let
| No | ReadonlyArray
| [10]
| Specify the available page sizes |
+| pagesUnknown | No | let
| No | boolean
| false
| Set to `true` if the number of pages is unknown |
+| pageText | No | let
| No | (page: number) => string
| (page) => \`page ${page}\`
| Override the page text |
+| pageRangeText | No | let
| No | (current: number, total: number) => string
| (current, total) => \`of ${total} page${total === 1 ? "" : "s"}\`
| Override the page range text |
+| id | No | let
| No | string
| "ccs-" + Math.random().toString(36)
| Set an id for the top-level element |
### Slots
diff --git a/docs/src/COMPONENT_API.json b/docs/src/COMPONENT_API.json
index ea4293b0..ac997ae7 100644
--- a/docs/src/COMPONENT_API.json
+++ b/docs/src/COMPONENT_API.json
@@ -10048,6 +10048,18 @@
"constant": false,
"reactive": false
},
+ {
+ "name": "pageWindow",
+ "kind": "let",
+ "description": "If `totalItems` is a large number, it can affect the\nrendering performance of this component since its value\nis used to calculate the number of pages in the native\nselect dropdown. This value creates a small window of\npages rendered around the current page. By default,\na maximum of 1000 select items are rendered.",
+ "type": "number",
+ "value": "1000",
+ "isFunction": false,
+ "isFunctionDeclaration": false,
+ "isRequired": false,
+ "constant": false,
+ "reactive": false
+ },
{
"name": "disabled",
"kind": "let",
diff --git a/docs/src/pages/components/Pagination.svx b/docs/src/pages/components/Pagination.svx
index 0ff1b471..0e54246b 100644
--- a/docs/src/pages/components/Pagination.svx
+++ b/docs/src/pages/components/Pagination.svx
@@ -19,6 +19,19 @@ components: ["Pagination", "PaginationSkeleton"]
+## Page window
+
+The number of native select items rendered is derived from the value of `totalItems`.
+
+If `totalItems` is a very large number, this can impact rendering performance since
+thousands of elements may be rendered. By default, the window of rendered items is
+capped at 1,000. For example, if `totalItems=100_000` and the `pageSize=10`,
+1,000 select options are rendered.
+
+Use the `pageWindow` prop to increase this value.
+
+
+
## Hidden page input
diff --git a/src/Pagination/Pagination.svelte b/src/Pagination/Pagination.svelte
index 1306e912..89b90b82 100644
--- a/src/Pagination/Pagination.svelte
+++ b/src/Pagination/Pagination.svelte
@@ -12,6 +12,16 @@
/** Specify the total number of items */
export let totalItems = 0;
+ /**
+ * If `totalItems` is a large number, it can affect the
+ * rendering performance of this component since its value
+ * is used to calculate the number of pages in the native
+ * select dropdown. This value creates a small window of
+ * pages rendered around the current page. By default,
+ * a maximum of 1000 select items are rendered.
+ */
+ export let pageWindow = 1000;
+
/** Set to `true` to disable the pagination */
export let disabled = false;
@@ -81,6 +91,21 @@
const dispatch = createEventDispatcher();
+ /**
+ * Returns a subset of page numbers centered around the current page to prevent
+ * performance issues with large datasets. Creates a capped window of pages
+ * instead of potentially thousands, improving render speed and memory usage.
+ * @param {number} currentPage - The current page number
+ * @param {number} totalPages - Total number of pages
+ * @param {number} window - How many pages to show before/after current page
+ * @returns {number[]} Array of page numbers to display
+ */
+ function getWindowedPages(currentPage, totalPages, window) {
+ const start = Math.max(1, currentPage - window);
+ const end = Math.min(totalPages, currentPage + window);
+ return Array.from({ length: end - start + 1 }, (_, i) => start + i);
+ }
+
afterUpdate(() => {
if (page > totalPages) {
page = totalPages;
@@ -89,7 +114,7 @@
$: dispatch("update", { pageSize, page });
$: totalPages = Math.max(Math.ceil(totalItems / pageSize), 1);
- $: selectItems = Array.from({ length: totalPages }, (_, i) => i);
+ $: selectItems = getWindowedPages(page, totalPages, pageWindow);
$: backButtonDisabled = disabled || page === 1;
$: forwardButtonDisabled = disabled || page === totalPages;
@@ -146,7 +171,7 @@
bind:selected={page}
>
{#each selectItems as size, i (size)}
-
+
{/each}
diff --git a/tests/Pagination/Pagination.test.svelte b/tests/Pagination/Pagination.test.svelte
index 63b4005e..64fdae79 100644
--- a/tests/Pagination/Pagination.test.svelte
+++ b/tests/Pagination/Pagination.test.svelte
@@ -11,6 +11,7 @@
export let pageSizeInputDisabled = false;
export let pageSize = 10;
export let pageSizes: ReadonlyArray = [10];
+ export let pageWindow: undefined | number = undefined;
export let pagesUnknown = false;
@@ -23,6 +24,7 @@
{itemsPerPageText}
{pageInputDisabled}
{pageSizeInputDisabled}
+ {pageWindow}
bind:pageSize
{pageSizes}
{pagesUnknown}
diff --git a/tests/Pagination/Pagination.test.ts b/tests/Pagination/Pagination.test.ts
index 027647d2..7345c214 100644
--- a/tests/Pagination/Pagination.test.ts
+++ b/tests/Pagination/Pagination.test.ts
@@ -196,4 +196,22 @@ describe("Pagination", () => {
expect(screen.getByText("0–0 of 0 items")).toBeInTheDocument();
});
+
+ it("renders a cap of 1000 page numbers by default", () => {
+ render(Pagination, {
+ props: { totalItems: 100_000 },
+ });
+
+ const pageNumbers = screen.getByLabelText(/Page number, of 10000 pages/);
+ expect(pageNumbers).toHaveLength(1_000 + 1);
+ });
+
+ it("renders a custom page window", () => {
+ render(Pagination, {
+ props: { totalItems: 100_000, pageWindow: 100 },
+ });
+
+ const pageNumbers = screen.getByLabelText(/Page number, of 10000 pages/);
+ expect(pageNumbers).toHaveLength(100 + 1);
+ });
});
diff --git a/types/Pagination/Pagination.svelte.d.ts b/types/Pagination/Pagination.svelte.d.ts
index 942aff98..8d0a9384 100644
--- a/types/Pagination/Pagination.svelte.d.ts
+++ b/types/Pagination/Pagination.svelte.d.ts
@@ -16,6 +16,17 @@ type $Props = {
*/
totalItems?: number;
+ /**
+ * If `totalItems` is a large number, it can affect the
+ * rendering performance of this component since its value
+ * is used to calculate the number of pages in the native
+ * select dropdown. This value creates a small window of
+ * pages rendered around the current page. By default,
+ * a maximum of 1000 select items are rendered.
+ * @default 1000
+ */
+ pageWindow?: number;
+
/**
* Set to `true` to disable the pagination
* @default false