Media & effects
Story Cards
Responsive interactive story cards carousel
detent-story-card
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-cinematic
- Group
- Media & effects
7.0 KB gzip for the class module
Variants
A local documentation carousel: the four stories are sample copy assigned as the cards property, with
no images and no network request. Use the Previous / Next controls, click a
preview card, scroll the track with a wheel or trackpad (or drag it horizontally), or focus a control and press the
arrow keys. The instance below has auto-play on: hovering it holds the story until you move away.
Neither it nor the main example emits a custom event, and with prefers-reduced-motion: reduce the
transitions and the autoplay are removed while every story stays reachable.
Recorded states
hoverrecorded state; no setterpausedrecorded state; no setterdraggingrecorded state; no setterreduced motionrecorded state; no setteractiverecorded state; no setter
Usage
Import
import '/components/story-card/define.js';
// or register it yourself
import { DetentStoryCards } from '/components/story-card/story-card.js';
Attributes
auto-playauto-play-intervalenable-wheel-scrollinitial-indexloopshow-navigationsubtitletitle
Properties
cards
Slots
No slots are recorded for this component.
Events
No events are recorded for this component.
Example
Runnable example: site/examples/story-card.ts. The snippet below is generated from the catalogued attributes.
<detent-story-card
auto-play
auto-play-interval="5000"
enable-wheel-scroll
initial-index="0"
loop
show-navigation
subtitle="Discover the latest stories."
title="What\'s happening"
></detent-story-card>
Property-only values
const element = document.querySelector('detent-story-card');
if (element !== null) {
// cards: StoryCard[]
element.cards = [];
}
Source
The pinned upstream source for this row:
src/components/ui/StoryCard.tsxsha256 0de1c5150e5a…
Native files
The native module and its artifacts:
src/components/story-card/story-card.tssrc/components/story-card/styles.csssrc/components/story-card/define.tsdocs/components/story-card.mdsite/examples/story-card.tstests/browser/story-card.spec.tsevidence/components/story-card.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 |
|---|---|---|---|---|
auto-play | autoPlay | boolean | false | Presence semantics: present means true, absent means false. |
auto-play-interval | autoPlayInterval | number | 5000 | Kebab-case attribute; camelCase property. |
enable-wheel-scroll | enableWheelScroll | boolean | true | Presence semantics: present means true, absent means false. |
initial-index | initialIndex | number | 0 | Kebab-case attribute; camelCase property. |
loop | loop | boolean | true | Presence semantics: present means true, absent means false. |
show-navigation | showNavigation | boolean | true | Presence semantics: present means true, absent means false. |
subtitle | subtitle | string | "Discover the latest stories." | Kebab-case attribute; camelCase property. |
title | title | string | "What\'s happening" | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
cards | StoryCard[] | undefined | 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.
- The pinned touchstart/touchend swipe becomes a Pointer Events drag with setPointerCapture at the same 40 px threshold, which is what makes the recorded dragging state observable; a click after a drag is suppressed so one gesture is one step.
- Arrow-key navigation is handled while focus is inside the component instead of on window, so several instances do not hijack arrow-key scrolling (PC-12.6).
- Preview cards are native buttons with aria-label Story: <title> and the active card is a labelled group with aria-current, instead of div role=button with re-implemented keyboard handling (PC-12.1).
- AnimatePresence per-child enter/exit becomes slot width and opacity transitions; the active content swap is immediate (motion fidelity stays an unresolved visual gate).
- initial-index is validated to 0..cards.length-1 with one warning and re-applied when the attribute changes.
- title/subtitle stay attributes; title is also the global HTMLElement.title attribute, so the heading and tooltip share it and no alias attribute is invented.
- The default demo dataset keeps the pinned copy but drops the four remote Unsplash image URLs (no network).
- Borders use #626b7a instead of the upstream hairline for 3:1 non-text contrast; the summary block renders the active description without a second CTA link.
What it does
A responsive story carousel: one expanded feature card, compact preview cards that navigate on click, infinite looping, wheel/trackpad and drag navigation, previous/next controls, arrow-key navigation and optional autoplay with hover pause.
Upstream behaviour
- Infinite loop carousel with continuous smooth transitions
- Responsive horizontal story card layout
- Large featured card with compact preview cards
- Mouse wheel and trackpad horizontal/vertical scroll support
- Touch swipe and drag gesture navigation
- Smooth spring-powered layout animations
- Previous and next navigation controls
- Clickable story previews for quick navigation
- Optional autoplay with configurable interval and hover pause
- Keyboard navigation with arrow keys
- Hardware accelerated animations
- Respects reduced-motion preferences
- Customizable appearance with standard Tailwind utility classes
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.
- The pinned touchstart/touchend swipe becomes a Pointer Events drag with setPointerCapture at the same 40 px threshold, which is what makes the recorded dragging state observable; a click after a drag is suppressed so one gesture is one step.
- Arrow-key navigation is handled while focus is inside the component instead of on window, so several instances do not hijack arrow-key scrolling (PC-12.6).
- Preview cards are native buttons with aria-label Story: <title> and the active card is a labelled group with aria-current, instead of div role=button with re-implemented keyboard handling (PC-12.1).
- AnimatePresence per-child enter/exit becomes slot width and opacity transitions; the active content swap is immediate (motion fidelity stays an unresolved visual gate).
- initial-index is validated to 0..cards.length-1 with one warning and re-applied when the attribute changes.
- title/subtitle stay attributes; title is also the global HTMLElement.title attribute, so the heading and tooltip share it and no alias attribute is invented.
- The default demo dataset keeps the pinned copy but drops the four remote Unsplash image URLs (no network).
- Borders use #626b7a instead of the upstream hairline for 3:1 non-text contrast; the summary block renders the active description without a second CTA link.