Detent web components
By Shane Logsdon

Navigation

SlidePagination

Implemented

Active indicator slides between pages

detent-slide-pagination

Port status
Catalog status
implemented
Origin
upstream
Phase
2
Wave
phase-2-navigation
Group
Navigation

5.5 KB gzip for the class module · inlines the shared spring

Variants

Recorded states

  • disabled recorded state; no setter
  • dark theme recorded state; no setter
  • active recorded state; no setter

Usage

Import

import '/components/slide-pagination/define.js';

// or register it yourself
import { DetentSlidePagination } from '/components/slide-pagination/slide-pagination.js';

Attributes

  • default-page
  • page
  • page-count
  • show-controls
  • sibling-count

Properties

  • pageCount
  • page
  • defaultPage
  • siblingCount
  • showControls
  • onChange

Slots

No slots are recorded for this component.

Events

  • detent-change — { page: number }

Example

Runnable example: site/examples/slide-pagination.ts. The snippet below is generated from the catalogued attributes.

<detent-slide-pagination
  default-page="1"
  page
  page-count
  show-controls
  sibling-count="1"
></detent-slide-pagination>

Property-only values

const element = document.querySelector('detent-slide-pagination');
if (element !== null) {
  // onChange: (page: number) => void
  element.onChange = () => {};
}

Source

The pinned upstream source for this row:

  • src/components/ui/SlidePagination.tsx sha256 7a619cdedb93…

Native files

The native module and its artifacts:

  • src/components/slide-pagination/slide-pagination.ts
  • src/components/slide-pagination/styles.css
  • src/components/slide-pagination/define.ts
  • docs/components/slide-pagination.md
  • site/examples/slide-pagination.ts
  • tests/browser/slide-pagination.spec.ts
  • evidence/components/slide-pagination.md

API

Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.

Attributes

Attributes
AttributePropertyTypeDefaultNotes
default-pagedefaultPagenumber1Kebab-case attribute; camelCase property.
pagepagenumberundefinedKebab-case attribute; camelCase property.
page-countpageCountnumberundefinedKebab-case attribute; camelCase property.
show-controlsshowControlsbooleantruePresence semantics: present means true, absent means false.
sibling-countsiblingCountnumber1Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
pageCountnumberundefinedProperty-only: assign from script; not accepted as an attribute.
pagenumberundefinedProperty-only: assign from script; not accepted as an attribute.
defaultPagenumber1Property-only: assign from script; not accepted as an attribute.
siblingCountnumber1Property-only: assign from script; not accepted as an attribute.
showControlsbooleantrueProperty-only: assign from script; not accepted as an attribute.
onChange(page: number) => voidundefinedProperty-only: assign from script; not accepted as an attribute.

Events

Events
EventUpstream propPayload typeNotes
detent-changeonChange(page: number) => voidComposed, bubbles; fires only for a user action.

Slots

No slots are recorded for this component.

CSS customisation

  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • The pill travels on two axes with the recorded springSnappy (380/30/0.5) via the shared helper instead of `layoutId`.
  • Upstream's docstring says items collapse and expand via AnimatePresence, but the pinned source imports no AnimatePresence and renders the windowed range without enter or exit motion (an upstream documentation defect). The native re-render matches that code: items do not animate in and out, and there is nothing to restore.
  • `show-controls` resolves true and is reflected, and the property is the opt-out (PC-3.2), so `show-controls="false"` is still true.
  • The requested page is stored unclamped and re-clamped when `page-count` changes, so a pre-definition `page` is never collapsed to 1.
  • Page changes are announced through one visually hidden `role="status"` region ("Page N of M", "No pages" when empty) - an upstream gap (PC-12.5).
  • Disabled controls keep `opacity: 1` and a muted colour instead of upstream `opacity-30`, which faded the icon below 3:1; lucide chevrons become a local decorative SVG and `className` maps to `part="nav"`.

What it does

A pagination control whose active pill travels between page buttons, with a windowed range (1 … 4 5 6 … 10), optional previous/next controls disabled at the boundaries, and a live announcement of the new page.

Upstream behaviour
  • Active background uses framer-motion shared layoutId for visible travel between pages
  • Snappy spring (springSnappy) drives the indicator for a precise, physical feel
  • Configurable siblingCount for windowed page ranges with ellipsis
  • Optional previous / next controls; disabled at boundaries
  • Light/dark theme aware — works in both palettes
Differences from upstream
  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • The pill travels on two axes with the recorded springSnappy (380/30/0.5) via the shared helper instead of `layoutId`.
  • Upstream's docstring says items collapse and expand via AnimatePresence, but the pinned source imports no AnimatePresence and renders the windowed range without enter or exit motion (an upstream documentation defect). The native re-render matches that code: items do not animate in and out, and there is nothing to restore.
  • `show-controls` resolves true and is reflected, and the property is the opt-out (PC-3.2), so `show-controls="false"` is still true.
  • The requested page is stored unclamped and re-clamped when `page-count` changes, so a pre-definition `page` is never collapsed to 1.
  • Page changes are announced through one visually hidden `role="status"` region ("Page N of M", "No pages" when empty) - an upstream gap (PC-12.5).
  • Disabled controls keep `opacity: 1` and a muted colour instead of upstream `opacity-30`, which faded the icon below 3:1; lucide chevrons become a local decorative SVG and `className` maps to `part="nav"`.
Previous: Skeleton Next: Compact Action Dock

Docs

Components

Project