Pagination
Project a large result set into direct pages and boundary controls.
Usage
Compact
Use a reduced control set when horizontal space is limited.
Use a reduced control set when horizontal space is limited.
<!-- Pagination / Compact -->
<script setup lang="ts">
import { PaginationRoot, PaginationFirst, PaginationPrevious, PaginationItem, PaginationNext, PaginationLast } from '@sectile/vue/pagination'
</script>
<template>
<PaginationRoot :total="240" :default-items-per-page="20" v-slot="{ items }">
<PaginationFirst>First</PaginationFirst>
<PaginationPrevious>Previous</PaginationPrevious>
<template v-for="item in items.filter(item => item.type !== 'control')" :key="JSON.stringify(item)">
<span v-if="item.type === 'ellipsis'" aria-hidden="true">…</span>
<PaginationItem v-else :item="item">{{ item.page }}</PaginationItem>
</template>
<PaginationNext>Next</PaginationNext>
<PaginationLast>Last</PaginationLast>
</PaginationRoot>
</template>Page size
Change the number of items per page and return to the first valid page when necessary.
Change the number of items per page and return to the first valid page when necessary.
<!-- Pagination / Page Size -->
<script setup lang="ts">
import { PaginationRoot, PaginationFirst, PaginationPrevious, PaginationItem, PaginationNext, PaginationLast } from '@sectile/vue/pagination'
</script>
<template>
<PaginationRoot :total="240" :default-items-per-page="20" v-slot="{ items }">
<PaginationFirst>First</PaginationFirst>
<PaginationPrevious>Previous</PaginationPrevious>
<template v-for="item in items.filter(item => item.type !== 'control')" :key="JSON.stringify(item)">
<span v-if="item.type === 'ellipsis'" aria-hidden="true">…</span>
<PaginationItem v-else :item="item">{{ item.page }}</PaginationItem>
</template>
<PaginationNext>Next</PaginationNext>
<PaginationLast>Last</PaginationLast>
</PaginationRoot>
</template>Pages only
Render direct page choices without first and last controls.
Render direct page choices without first and last controls.
<!-- Pagination / Pages Only -->
<script setup lang="ts">
import { PaginationRoot, PaginationFirst, PaginationPrevious, PaginationItem, PaginationNext, PaginationLast } from '@sectile/vue/pagination'
</script>
<template>
<PaginationRoot :total="240" :default-items-per-page="20" v-slot="{ items }">
<PaginationFirst>First</PaginationFirst>
<PaginationPrevious>Previous</PaginationPrevious>
<template v-for="item in items.filter(item => item.type !== 'control')" :key="JSON.stringify(item)">
<span v-if="item.type === 'ellipsis'" aria-hidden="true">…</span>
<PaginationItem v-else :item="item">{{ item.page }}</PaginationItem>
</template>
<PaginationNext>Next</PaginationNext>
<PaginationLast>Last</PaginationLast>
</PaginationRoot>
</template>Controlled
Let the parent own the current value and apply accepted changes back to the component.
Let the parent own the current value and apply accepted changes back to the component.
<!-- Pagination / Controlled -->
<script setup lang="ts">
import { PaginationRoot, PaginationFirst, PaginationPrevious, PaginationItem, PaginationNext, PaginationLast } from '@sectile/vue/pagination'
</script>
<template>
<PaginationRoot :total="240" :default-items-per-page="20" v-slot="{ items }">
<PaginationFirst>First</PaginationFirst>
<PaginationPrevious>Previous</PaginationPrevious>
<template v-for="item in items.filter(item => item.type !== 'control')" :key="JSON.stringify(item)">
<span v-if="item.type === 'ellipsis'" aria-hidden="true">…</span>
<PaginationItem v-else :item="item">{{ item.page }}</PaginationItem>
</template>
<PaginationNext>Next</PaginationNext>
<PaginationLast>Last</PaginationLast>
</PaginationRoot>
</template>Examples
Long range
Navigate a large result set without rendering every page number.
Navigate a large result set without rendering every page number.
<!-- Pagination / Long Range -->
<script setup lang="ts">
import { PaginationRoot, PaginationFirst, PaginationPrevious, PaginationItem, PaginationNext, PaginationLast } from '@sectile/vue/pagination'
</script>
<template>
<PaginationRoot :total="240" :default-items-per-page="20" v-slot="{ items }">
<PaginationFirst>First</PaginationFirst>
<PaginationPrevious>Previous</PaginationPrevious>
<template v-for="item in items.filter(item => item.type !== 'control')" :key="JSON.stringify(item)">
<span v-if="item.type === 'ellipsis'" aria-hidden="true">…</span>
<PaginationItem v-else :item="item">{{ item.page }}</PaginationItem>
</template>
<PaginationNext>Next</PaginationNext>
<PaginationLast>Last</PaginationLast>
</PaginationRoot>
</template>API
Vue package: @sectile/vue/pagination
PaginationRootPaginationItemPaginationFirstPaginationPreviousPaginationNextPaginationLast
Props
PaginationRootProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
defaultItemsPerPageInitial uncontrolled number of records shown per page.
defaultValueInitial value used when the component owns its state.
disabledWhether interaction is unavailable.
getControlLabelReturns the accessible label announced for a pagination control.
getPageLabelReturns the accessible label announced for a page choice.
itemsPerPageControlled number of records shown per page.
labelAccessible name announced for the control.
modelValueCurrent value when state is controlled by the parent.
readonlyWhether the value can be inspected but not changed.
showControlsWhether first, previous, next, and last controls are included.
showEdgesWhether the first and last page numbers remain visible.
siblingCountNumber of adjacent page choices shown around the current page.
totalTotal number of records represented by pagination.
PaginationItemProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
itemPagination item rendered by this part.
Slots
PaginationRootSlotProps
itemsCurrent derived item collection.
itemsPerPageNumber of records currently shown per page.
pageCurrent one-based page number.
pageCountTotal number of available pages.
rangeCurrent start and end values.
PaginationItemSlotProps
disabledWhether interaction is unavailable.
itemCurrent pagination item.
selectedWhether this item is selected.
Events
PaginationRoot
update:itemsPerPageEmitted when the requested page size changes.
update:modelValueEmitted when the component requests a new controlled value.
Other types
PaginationPageLabelResolver
type PaginationPageLabelResolver = NonNullable<PaginationRootProps['getPageLabel']>PaginationControlLabelResolver
type PaginationControlLabelResolver = NonNullable<PaginationRootProps['getControlLabel']>PaginationValueChangeHandler
type PaginationValueChangeHandler = (value: number) => voidPaginationItemsPerPageChangeHandler
type PaginationItemsPerPageChangeHandler = (value: number) => voidParts
Shared scope: [data-scope="pagination"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
first | [data-part="first"] | Moves to the first page. | — |
previous | [data-part="previous"] | Moves to the previous item or page. | — |
item | [data-part="item"] | Represents one selectable or actionable item. | — |
next | [data-part="next"] | Moves to the next item or page. | — |
last | [data-part="last"] | Moves to the last page. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Tab | Move between pagination controls exposed as native buttons or links. |
| Enter / Space | Activate the focused page or boundary control. |
| Home / End | The terminal projection moves to the first or last page. |
Accessibility
Page links or buttons keep native activation semantics and identify the current page without relying on position alone.
