Media & effects
Stacked Cards
Scroll-driven sticky stacking cards
detent-stacked-cards
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-cinematic
- Group
- Media & effects
4.8 KB gzip for the class module
Variants
A local documentation deck: the three cards above are sample copy assigned as the cards property, with no
images and no network request. Scroll the page so the section passes the viewport: each card pins
16px lower than the previous one and scales down by 0.075 per covering card, on native
position: sticky and native window scrolling. With prefers-reduced-motion: reduce the scale
is removed entirely and the cards simply stack.
Recorded states
light themerecorded state; no setterreduced motionrecorded state; no setter
Usage
Import
import '/components/stacked-cards/define.js';
// or register it yourself
import { DetentStackedCards } from '/components/stacked-cards/stacked-cards.js';
Attributes
subtitletitle
Properties
cards
Slots
No slots are recorded for this component.
Events
No events are recorded for this component.
Example
Runnable example: site/examples/stacked-cards.ts. The snippet below is generated from the catalogued attributes.
<detent-stacked-cards
subtitle
title
></detent-stacked-cards>
Property-only values
const element = document.querySelector('detent-stacked-cards');
if (element !== null) {
// cards: StackedCard[]
element.cards = [];
}
Source
The pinned upstream source for this row:
src/components/ui/StackedCards.tsxsha256 ec863b52fba4…
Native files
The native module and its artifacts:
src/components/stacked-cards/stacked-cards.tssrc/components/stacked-cards/styles.csssrc/components/stacked-cards/define.tsdocs/components/stacked-cards.mdsite/examples/stacked-cards.tstests/browser/stacked-cards.spec.tsevidence/components/stacked-cards.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 |
|---|---|---|---|---|
subtitle | subtitle | string | undefined | Kebab-case attribute; camelCase property. |
title | title | string | undefined | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
cards | StackedCard[] | defaultCards | Property-only: assign from script; not accepted as an attribute. |
Events
No custom events are recorded for this component.
Slots
No slots are recorded for this component.
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- index, total, card and progress are private CardItemProps in the pinned source; the host derives them from the cards array and the section scroll, so the row lists only title/subtitle attributes and cards as a property.
- The default demo dataset keeps the pinned copy but drops the four remote Unsplash image URLs; a component must not perform third-party network requests, and image/imageAlt stay consumer-supplied under the R-3 scheme allow-list.
- A card without an allowed image URL renders the documented media gradient placeholder because there is no local upstream asset to ship.
- Card borders use #626b7a/#6b7280 instead of the upstream hairline for the 3:1 non-text ratio (PC-12.6).
What it does
A column of story cards that stays aligned in the initial view and stacks on scroll: every card is a sticky wrapper around an article that scales down as the next card covers it.
Upstream behaviour
- Naturally aligned column layout in the initial view
- Scroll-driven sticky stacking where cards stack one above another on scroll
- Non-blocking native window scrolling — continues to subsequent sections seamlessly
- Responsive two-column grid on desktop, single-column on mobile
- Dark and light mode compatible with high-contrast typography and borders
- Hardware accelerated motion transitions with subtle depth shadow
- Respects prefers-reduced-motion preferences
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- index, total, card and progress are private CardItemProps in the pinned source; the host derives them from the cards array and the section scroll, so the row lists only title/subtitle attributes and cards as a property.
- The default demo dataset keeps the pinned copy but drops the four remote Unsplash image URLs; a component must not perform third-party network requests, and image/imageAlt stay consumer-supplied under the R-3 scheme allow-list.
- A card without an allowed image URL renders the documented media gradient placeholder because there is no local upstream asset to ship.
- Card borders use #626b7a/#6b7280 instead of the upstream hairline for the 3:1 non-text ratio (PC-12.6).