Swipeable, scroll-snap pager with typed page ids and a segmented tab bar (APG tabs).
|
|
| Package |
@vizejs/ui/pager |
| Maturity |
stable |
| Own the source |
vize lib pull pager |
| Requires |
context, controllable-state, id |
| Aliases |
view pager, swipe tabs, segmented pager, page view, swipeable views |
| Covers |
WAI-ARIA Tabs, CSS scroll snap, Android ViewPager2, UIPageViewController |
Usage
import { Pager, PagerTabList, PagerTab, PagerViewport, PagerPage } from "@vizejs/ui/pager";
Or copy the source into your project with vize lib pull pager (see Source Distribution).
API
Source: src/families/navigation/pager/pager.vue
Props
| Prop |
Type |
Default |
Description |
pages (required) |
readonly PageId[] |
required |
Page ids in order; their literal union types v-model and change. |
modelValue |
PageId |
undefined |
Controlled active page. undefined selects uncontrolled behavior. |
defaultValue |
PageId |
pages[0] |
Initial uncontrolled page. |
id |
string | null |
undefined |
Base id for tabs and panels. null and undefined select a deterministic fallback. |
Events
| Event |
Payload |
Description |
update:modelValue |
[page: PageId] |
Fired when the active page requests a change. |
change |
[page: PageId, previous: PageId, reason: PagerChangeReason] |
Fired after the active page changes, with the previous page and what caused it. |
Slots
| Slot |
Slot props |
Description |
default |
PagerSlotState<PageId> |
Renders PagerTabList and PagerViewport with the typed page state. |
Exposed
| Member |
Type |
Description |
pages |
readonly PageId[] |
Page ids in order. |
active |
PageId |
Active page. |
index |
number |
Zero-based index of the active page. |
count |
number |
Number of pages. |
goTo |
(page: PageId) => boolean |
Scroll to a page and make it active. |
next |
() => boolean |
Go to the next page (no wrap); returns whether it moved. |
previous |
() => boolean |
Go to the previous page (no wrap); returns whether it moved. |
Source: src/families/navigation/pager/pager-tab-list.vue
Props
| Prop |
Type |
Default |
Description |
ariaLabel |
string |
undefined |
Accessible name of the tab list. |
Slots
| Slot |
Slot props |
Description |
default |
Record<string, never> |
PagerTab segments, in page order. |
Source: src/families/navigation/pager/pager-tab.vue
Props
| Prop |
Type |
Default |
Description |
page (required) |
string |
required |
Page this segment selects; must be one of the Pager pages. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly selected: boolean } |
Segment label with its selection state. |
Source: src/families/navigation/pager/pager-viewport.vue
Props
| Prop |
Type |
Default |
Description |
settleDelay |
number |
120 |
Quiet period (ms) after the last scroll event before a user scroll settles, for engines without scrollend. |
Slots
| Slot |
Slot props |
Description |
default |
Record<string, never> |
PagerPage panels, in page order. |
Source: src/families/navigation/pager/pager-page.vue
Props
| Prop |
Type |
Default |
Description |
page (required) |
string |
required |
Page id this panel renders; must be one of the Pager pages. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly active: boolean } |
Page contents; stay mounted so swiping shows neighbors. |
Behavior
Normative state x input -> outcome table for pager.vue, pager-tab-list.vue,
pager-tab.vue, pager-viewport.vue, and pager-page.vue
(@vizejs/ui/pager): a swipeable, scroll-snap page view whose segmented tab bar
follows the WAI-ARIA APG tabs pattern with automatic activation. pages infers
the page-id union. Minimal consumer CSS: the viewport is display: flex; overflow-x: auto; scroll-snap-type: x mandatory and pages are flex: 0 0 100%; scroll-snap-align: start. Every row is proven by the named test in
pager.test.ts or pager-ssr.test.ts.
| # |
State |
Input |
Outcome |
Proven by |
| PG1 |
seeded |
render |
labelled tablist; selected tab is the roving tab stop wired to its tabpanel; off-screen panels are inert |
renders APG tabs wired to scroll-snap pages with inert off-screen panels |
| PG2 |
any |
tab click |
the page becomes active, the viewport smooth-scrolls to it, and change(page, previous, "tab") fires |
selecting a tab scrolls the viewport smoothly and emits typed changes |
| PG3 |
focused tablist |
Arrow / Home / End |
arrows (RTL-aware) wrap, Home/End jump; focus and selection move together |
arrow keys, Home, and End move the selected segment with wrapping |
| PG4 |
swiping |
scroll quiet period / scrollend |
the page nearest the scroll position becomes active with reason scroll; programmatic scrolls never re-select; next/previous stop at the ends |
user swipes settle on the nearest page while programmatic scrolls are ignored |
| PG5 |
controlled / reduced motion |
parent change |
controlled values win and parent changes scroll the viewport; reduced motion scrolls with behavior: "auto" |
controlled pages scroll when the parent changes them and reduced motion scrolls instantly |
| PG6 |
invalid setup |
empty pages / missing root |
throws VIZE_UI_PAGER_PAGES or VIZE_UI_CONTEXT_MISSING: Pager |
rejects empty page lists and parts outside a Pager |
| PG7 |
SSR / hydration |
isolated requests |
byte-identical tabs and panels; the initial page is scrolled into place only after hydration |
renders byte-identical tabs and pages and hydrates without mismatches |
The subpath ships no CSS.