Media & effects
Sticky Pages
Static sticky full-page stacking scroll sections with clean physical shadows and natural release
detent-sticky-pages
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-cinematic
- Group
- Media & effects
01. Architected for speed
Slotted page — consumer markup and consumer styles.
02. Modern aesthetic system
Each page pins under the previous one.
03. Production grade components
The last page releases back into natural scrolling.
4.5 KB gzip for the class module
Variants
Slot composition — the pages in the main example are real light-DOM children of
detent-sticky-pages. They are never moved, cloned, clipped or trapped: scroll the page and each one
pins under the previous one with its own surface, then the last page releases into normal flow. Reduced motion keeps
the exact same layout with the shadow transition removed.
Data composition — the same stacking from a pages property: badge, counter, title and
description are laid out by the component (documentation demo copy only). The third page overrides the surface with
its own themed bg token.
Recorded states
reduced motionrecorded state; no setter
Usage
Import
import '/components/sticky-pages/define.js';
// or register it yourself
import { DetentStickyPages } from '/components/sticky-pages/sticky-pages.js';
Attributes
bgborderpage-heightroundedshadowstack-offsettop-offset
Properties
pages
Slots
default
Events
No events are recorded for this component.
Example
Runnable example: site/examples/sticky-pages.ts. The snippet below is generated from the catalogued attributes.
<detent-sticky-pages
bg
border
page-height="100vh"
rounded
shadow
stack-offset="0"
top-offset="0"
></detent-sticky-pages>
Property-only values
const element = document.querySelector('detent-sticky-pages');
if (element !== null) {
// pages: StickyPageItem[]
element.pages = [];
}
Source
The pinned upstream source for this row:
src/components/ui/StickyPages.tsxsha256 8e547c91eda5…
Native files
The native module and its artifacts:
src/components/sticky-pages/sticky-pages.tssrc/components/sticky-pages/styles.csssrc/components/sticky-pages/define.tsdocs/components/sticky-pages.mdsite/examples/sticky-pages.tstests/browser/sticky-pages.spec.tsevidence/components/sticky-pages.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
bg | — | — | — | Recorded in the catalog as an attribute. |
border | border | boolean | true | Presence semantics: present means true, absent means false. |
page-height | pageHeight | string | '100vh' | Kebab-case attribute; camelCase property. |
rounded | rounded | boolean | true | Presence semantics: present means true, absent means false. |
shadow | shadow | boolean | true | Presence semantics: present means true, absent means false. |
stack-offset | stackOffset | number | 0 | Kebab-case attribute; camelCase property. |
top-offset | topOffset | number | 0 | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
pages | StickyPageItem[] | — | Property-only: assign from script; not accepted as an attribute. |
Events
No custom events are recorded for this component.
Slots
| Slot | Notes |
|---|---|
default | Consumer content; rendered through a slot, never re-created. |
CSS customisation
- React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- index and total are StickyPageCardProps internals derived from composition order and length, not host API; the row lists only the geometry attributes and pages.
- pages[].content has no native data equivalent; rich pages are supplied through the default slot, which keeps the consumer DOM, listeners and focus.
- rounded, shadow and border are declared but never read in the pinned source; they are implemented here because the row records them as API.
- data-active, data-active-index and the covering page elevated shadow are native additions derived from the pinned index.
- Slotted pages receive --detent-sticky-pages-index and --detent-sticky-pages-active so any number of light-DOM children get per-index sticky geometry without being moved or cloned.
- StickyPage is a thin wrapper with no native need and StickyStack/StackingPages are pure aliases; one tag and one class per PC-2.2/PC-13.1.
- Page borders use #626b7a for the 3:1 non-text contrast.
What it does
Full-page sections that pin under native position: sticky and stack over one another as the document scrolls, then release back into normal flow. Zero tilting, zero rotation, zero transform distortion, zero scroll hijacking.
Upstream behaviour
- Pure static stacking: zero tilting, zero rotation, zero transform distortion
- Native browser scrolling: zero scroll hijacking or wheel locking, built on native CSS position: sticky
- Stacking depth: each page slides up directly over the previous one with elevated top shadows and rounded borders
- Natural release: once the final page finishes stacking, the container seamlessly transitions back into normal document flow
- Dual composition support: pass a structured pages data array or arbitrary <StickyPage> child components
- Configurable top offset, stack offset, page height, rounded corners, and drop shadows
- Full prefers-reduced-motion compliance maintaining standard clean sticky reading
Differences from upstream
- React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- index and total are StickyPageCardProps internals derived from composition order and length, not host API; the row lists only the geometry attributes and pages.
- pages[].content has no native data equivalent; rich pages are supplied through the default slot, which keeps the consumer DOM, listeners and focus.
- rounded, shadow and border are declared but never read in the pinned source; they are implemented here because the row records them as API.
- data-active, data-active-index and the covering page elevated shadow are native additions derived from the pinned index.
- Slotted pages receive --detent-sticky-pages-index and --detent-sticky-pages-active so any number of light-DOM children get per-index sticky geometry without being moved or cloned.
- StickyPage is a thin wrapper with no native need and StickyStack/StackingPages are pure aliases; one tag and one class per PC-2.2/PC-13.1.
- Page borders use #626b7a for the 3:1 non-text contrast.