Pagination handbook
v1.6.4 · @snowui-design-system/components
License: Before reading component documentation, source, or npm usage instructions for the first time, read the full LICENSE. Reuse that review for the same task and version. Public API configuration and internal implementation changes have different license implications. All components use the unified runtime package; source rights remain governed by the license.
Overview
Provide page navigation for paged tables, lists, and search results.
When to use it
Use it for navigation between pages of content. DataTable can bind to its page state; the page or data layer remains responsible for fetching data.
Pages are numbered from 1.
totalis the number of pages, not the number of rows; useonPageChangeto update page state.pageSizeOptionsconfigures page-size choices andpageSizecan be bound. The page or DataTable fetches data and calculates the total number of pages.The default navigation name follows LocaleProvider; an explicit ariaLabel takes priority. Page numbers, page size and responsibility for business requests are unchanged.
Quick start
This example shows the recommended basic composition. See the sections below for more cases and composition limits.
API
See the base component documentation for inherited capabilities not redeclared here. This table lists only named public Props declared by this component.
Usage boundaries and details
Built-in component dual mode
parts.Button: Configure the default built-in button templates.parts.Listbox: Configure the page-size Listbox owned by Pagination.parts.MenuItem: Configure the page-size options.Use the existing
astemplates or an external selector for structural changes. Explicit Props on a template take precedence overparts.
Pagination defaults to the built-in Button role template, and generates real page numbers according to page and total. The explicit children can replace the default template.
Pagination is a basic navigation component. Its scope is its own nav, direct role templates, and generated items; it does not manage the layout of surrounding components.
Feature overview
Default built-in mode: the current page uses gray Button, and the ordinary page, the previous page and the next page use the outline Button.
The pageSize is located on the left side by default and keeps Hug; the page button group is located on the right side, with a default interval of 16px from pageSize.
In the default fill mode, current, page, prev and next always fill in the remaining space with equal widths; the ellipsis remains Hug.
Explicit composition mode: Child Buttons define the style of each role; they do not represent individual data pages.
Based on
page,total, and available width, show all page numbers when possible or insert…automatically. There is no manual window-size Prop.Use the built-in default arrow when the
prev/nexttemplate is missing.The clickability of the current page, the boundary prev / next, the whole disabled, and the single page disabled are all managed by Pagination.
Pagination does not control the variant / size / hover color / border / background of the user's Button template; as a composite navigation control, only the button hover of the item is enlarged and turned off by default, and the template can be overwritten by
scaleOnHover={true}.Pagination supports three clear width modes:
auto,hugandfill.With
responsive="auto", show all page numbers when possible. As space decreases, insert ellipses, hide the page-size selector, then reduce the page-number window. Previous and next controls remain available.When
pageSizeOptionsandButton as="pageSize"are provided, show the page-size selector.The declaration order of the
pageSizetemplate in children determines whether the selector is on the left or right side of the page number.Pagination only provides a group of
variantmatching; the size, color, hover, border and other visuals of a single character are still configured through the Button template.The default page number and front and back pages of Pagination use the built-in Button template; ellipsis use internal text, and arrows use built-in ComponentIcon.
Core attributes
total will be normalized to at least 1. page will be normalized to [1, total] to avoid rendering cross-boundary page numbers.
Sub-level role
The current / page template does not need to write the content. When Pagination renders, the real page number will be injected, and there is no need to write value or data-page.
Template rules:
What is written in Pagination is equivalent to defining a style for the role.
When there are multiple direct templates in the same role, only the first one is used.
When the
currenttemplate is missing, use the built-in current page Button withvariant.When the
pagetemplate is missing, use the built-in ordinary page Button specified byvariant.When the
prev/nexttemplate is missing, use the built-in Button specified byvariantand the defaultArrowLineLeft/Righticon.The custom Button template retains its own variant, size, padding, radius, hover, focus, border and background.
The Button generated by Pagination defaults to
scaleOnHover=false; the template reserves the amplification feedback when the template explicitly transmitsscaleOnHover={true}.Pagination only takes over the generated width mode, page number text, clickability and accessibility status.
Basic usage
The default style is Hug pageSize on the left (displayed when pageSizeOptions is provided) and Fill page group on the right; the current page is gray, and the rest of the button is outline.
Button style matching
variant describes the normal style of the normal page, previous page and next page buttons. Pagination will automatically select an emphasis style with sufficient distinction for the current page:
The explicitly provided current, page, prev or next Button templates are still subject to the template's own variant, which is suitable for scenes that need to be separated from the built-in matching.
Responsive contraction
responsive="auto" enables content measurement strategies similar to OverflowActions by default. Fill mode reads the width of Pagination itself; Auto / Hug mode reads the real available width of the parent container, multi-column Grid only uses the width of the track where Pagination is located, and horizontal Flex deducts the same-level content and Gap. Therefore, after shrinkage, it can still be restored step by step with the continuous expansion of the outer layer, and will not borrow the space of adjacent titles or controls. The strategy does not rely on the viewport breakpoint and shrinks step by step in the following order:
Full page number: Try to display all page numbers from
1tototalfirst. When the number of pages is small and there is enough space,fill/autocan make the button width full; the button shrinks to the lower limit of its own content width without changing the size, padding, font size or click height.Contents of front and back pages: If the
prev/nexttemplate contains Icon and ordinary text or Text at the same time, hide the text first and switch to icon-only padding when there is not enough space;aria-labelkeeps "previous page" or "next page".Anchored ellipses: When all numbers do not fit, keep the first, last, and nearby current pages, inserting non-interactive ellipses between gaps.
Hide pageSize: If there is a page number selector, hide it first in the next stage, and leave the available width to the paging navigation.
Current-page navigation: When the anchored layout is still too wide, remove the first and last anchors and ellipses, keeping current, previous, and next.
Minimum navigation: Finally hide the current page, leaving only previous and next. Natural overflow is allowed below their physical minimum width.
The pageSize Listbox freezes the current response stage during the opening period to avoid the reconstruction of the floating layer anchor point in the operation; refresh according to the latest width after the floating layer is closed. When the width is restored, the above stages are restored in reverse order. Size monitoring unified resizeManager sharing resizeManager; responsive="none" can turn off dynamic compression and retain static windows and traditional line breaks.
Select the number of bars per page
pageSize is on the left when written before the page number template; on the right side when written after the page number template:
Pagination clones the Button template as a Listbox trigger, so the visual is controlled by Button's variant, size and style, and the option panel, keyboard navigation, Portal and selection status are managed by the built-in Listbox service. The selector is not rendered when Button as="pageSize" is not declared or pageSizeOptions is not passed.
The default arrow of pageSize uses the Components semantics arrow-line-down icon. It uses the same --snowui-pagination-icon-size size entrance as arrow-line-left / arrow-line-right; the Icon wrapper, Icon Frame and internal SVG of pageSize all converge to this size to avoid Icon default size overflow. Icon is the ordinary content of Button, not marked with as="trailing"; the horizontal centering and spacing of the text and Icon inherits Button's own content layout and gap. The pageSize shell and Button template are always Hug, and do not participate in the Fill allocation of the page number button.
Pagination internally organizes the page number and prev / next into a page button group. pageSizeGap only controls the spacing between pageSize and this button group, and the ordinary column-gap of Pagination is still used inside the button group:
Gap and inline style priority
The public spacing API does not require the use of Token or CSS variables:
gap: Spacing within the page-button group.pageSizeGap: Spacing between the page-size selector and the button group.Numbers are parsed as pixels; CSS lengths such as "0.75rem" and "clamp(...)" are also supported. Both effective gaps retain at least 4 CSS px, including explicit zero and small root font sizes. Larger values are preserved.
The root node inline style follows the highest priority of Level 6 of StyleSpec §2.6 (source code reference: specs/maintainers/StyleSpec.md) and is mapped to the current valid area by Pagination:
Within the 4 CSS px floor, preferred spacing retains this priority: inline style gap > corresponding explicit prop > Pagination default. With pageSize present, inline gap does not replace the internal group gap because the two control different levels.
Pagination only recognizes the direct role template. Do not use div to wrap Button as="current" / Button as="page" to create a left and right layout; the nested template will be ignored and returned to the default page number. Adjusting the left and right positions of pageSize should directly change the order of the direct template.
Completely external and complex layout
The number of bars per page can also be completely managed by the page. Pagination does not require the selector to be its own sub-item:
This way of writing is suitable for pages that are divided into columns, arranged up and down, or where the selector does not belong to the paging navigation area.
Eventually, it will render close to 1 2 3 4 5 < >. When prev / next is not provided, Pagination uses the built-in default arrow.
Fill button width
Current, page, previous, and next buttons divide the space left after ellipses; generated ellipses keep their content width. Empty Button as="prev" and Button as="next" templates define only appearance.
Forced Hug
Custom role template
Pagination only copies the appearance attributes of the template and replaces the page number text; clicks and availability are managed by Pagination.
Single-page disabled
Page 3 will be marked as unclickable, and other non-current pages can still trigger onPageChange.
Design draft style restoration
This example uses the variant of the Button and the design draft ArrowLineLeft/Right SVG to restore the gray background current page, the stroke ordinary page and the stroke arrow button in Figma.
Completely default style
When the sub-level template is not passed at all, Pagination will use the built-in Button and arrow icon to generate all the visible items.
Controlled page number
onPageChange will only be triggered when the target page can be clicked. The current page, disabled page, cross-bound page, the prev of the first page, and the next of the last page will not trigger the callback.
Rules of conduct
If all
totalpage numbers fit, show every page without an ellipsis.When all pages do not fit, retain the first, last, and nearby current page numbers and insert ellipses at each gap.
The current page outputs
aria-current="page",data-current="page",aria-disabled="true", which cannot be clicked.When
page <= 1, prev cannot be clicked.When
page >= total, next cannot be clicked.The page number in
disabledPagescannot be clicked; prev / next will skip the continuous disabled page and point to the nearest available page in this direction; it cannot be clicked when there is no available page in this direction.All generated items cannot be clicked when
disabled={true}.The ellipsis cannot be clicked and does not enter the focus sequence.
widthMode="fill"stretches the page and previous/next buttons. Ellipses and the page-size selector keep their content width.responsive="auto"The page control line does not change lines, and the page number window is selected according to the actual measurement width of the container;prevandnextare never hidden.pageSize is hidden before the ellipsis and the current page under the narrow width; the current stage is frozen when Listbox is opened.
Page number window compensation rules:
Near the first page, show more consecutive starting pages, such as
1 2 3 … 22.Near the middle, show ellipses on both sides, such as
1 … 10 11 12 … 22.Near the last page, show more consecutive ending pages, such as
1 … 20 21 22.
Click and disable rules:
Disabled-state priority: overall disabled > no available page in the previous/next direction > disabledPages > current page.
Accessibility rules:
The root element semantics is
nav, and the default isaria-label="Pagination".The current page must output
aria-current="page".Unavailable items use
aria-disabled="true"and are removed from the normal Tab order.Inserted ellipses use
aria-hidden="true"and cannot receive focus.
Default style
When the role template is missing, Pagination gives priority to the built-in Button template of the selected variant. The following snowui-pagination-default-* rule is only used as a defensive return when the template node is unavailable:
Text and Icon hover without a background follow StyleSpec §2.4.5 (source: specs/maintainers/StyleSpec.md): black/100% × opacity: 0.4 → 1. No background overlay is used.
Figma comparison:
Layout model
Main layout model: inline shell layout. See LayoutProtocol §12.4 (source: specs/maintainers/LayoutProtocol.md).
The root container is
nav.The root uses
inline-flexandmin-width: 0, so it can shrink according to the true width of the parent container in the Grid/Flex sub-item; in the automatic response mode, pageSize maintains the same line as the page control, and the pageSize is hidden by the component when there is not enough space.responsive="auto"When the paging control is kept a single line internally, and the page number adapts the width by omitting the policy;nonerestores the traditional internal line interaction.The default gap is
4px.widthMode="auto": When the Pagination itself is Hug width, the internal button Hug; when the width is fixed or stretched, the button automatically equals the width Fill.widthMode="hug": The root width is fit-content, and the button and ellipsis remain Hug.widthMode="fill": The root width is 100%; the remaining space is equally divided between the page number and the front and rear page turning buttons, and the remaining space is also filled when there is an ellipsis.When the auto mode cannot be determined stably, give priority to Hug to avoid accidental stretching in the content width container.
Structural model:
Layout variable chain:
Style boundary
Pagination does not rewrite the variant of the user's Button template through context.
Pagination does not rewrite the hover, active, focus, disabled, border, background, padding and radius of the user's Button template.
Pagination only allows you to control the width mode, clickability, and root container gap / wrap / align of the generated elements.
The custom visual differences between the current page, the non-current page, the previous page and the next page are expressed by the role template.
Pagination owns the generated ellipses. Their font, line height, color, and width behavior can be configured through Pagination variables.
Use
:global(:where(...))to keep CSS selector specificity low.Transition consumes Frame bridge variables to avoid the private animation timing of hard-coded components.
Pagination style overlay
Read the full LICENSE first; reuse that review for the same task, version, and scope.
First use public component Props to match the desired appearance, preserving the existing look where possible. If changes are necessary, follow the style selection and override order: use your own class (including Tailwind already in the project) or an instance style. The names below are public overrides actually consumed by source; check their scope and do not modify private DOM. Choose the correct SnowUI token family. External apps need not install SnowUI website utilities.
Pagination type and status
Required Props: no named required Props.
Bidirectional binding: bind:pageSize.
Inheritance statement: Omit<FrameProps, "children" | "gap">. The inheritance ability is subject to the public document of the base class; the fields in Omit have been excluded and cannot be used as they are according to the base class.
The following type declarations are actually referenced by public Props and come from source. A Svelte Snippet denotes a content fragment; ComponentProps denotes the Props of the corresponding component.
PaginationVariant
Source: components/src/components/Pagination.svelte
PaginationResponsive
Source: components/src/components/Pagination.svelte
PaginationWidthMode
Source: components/src/components/Pagination.svelte
ComponentPartsOf
Source: components/src/logic/component-parts.svelte.ts
ConfigurableComponentPartProps
Source: components/src/logic/component-parts.svelte.ts
ComponentPartControlledKey
Source: components/src/logic/component-parts.svelte.ts