Marble UI
← Components

Stories / Reel / Deck

Preview: Default

Story rail + full-screen viewer: segmented progress, auto-advance (5s), tap/click left-right or arrow keys, Space or press-and-hold to pause, Escape closes. Seen stories lose their ring.

Import

import { Stories } from '@marbleui/ui'

Props

<Stories>

PropTypeDefaultDescription
stories *requiredStory[]—
classNamestring—
durationnumber5000

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria Button · React Aria Dialog · React Aria Modal · React Aria ModalOverlay. Follow the primitive's docs for the full keyboard map.

Usage notes

Row of avatar buttons that opens a full-screen, auto-advancing story viewer, for short visual updates from people or teams. For slides the reader moves through at their own pace, use Carousel.

<Stories
  duration={6000}
  stories={[
    { id: 'maya', author: 'Maya Chen', slides: [{ src: '/stories/launch.jpg', alt: 'Launch banner on the office wall', caption: 'We shipped v2' }] },
    { id: 'leo', author: 'Leo Martins', slides: [{ src: '/stories/offsite.jpg', alt: 'Team hiking at the offsite' }] },
  ]}
/>
  • Each slide shows for duration ms (default 5000), then the viewer advances to the next slide or story and closes after the last one.
  • ←/→ change slides, Space or the Pause button pauses and resumes, Escape closes. Tapping the left third goes back and the rest goes forward. Press-and-hold pauses until release, and the release doesn’t change the slide; a story paused with Space stays paused after a tap.
  • The dialog is labelled “{author}’s story, n of N” and each image uses its alt; slide changes aren’t announced.
  • Seen rings live in component state only: they reset on remount and there’s no callback to persist them.
Example source · show
import { demoImage } from '../lib/demo-images'
import { Stories } from './stories'

const people = ['Maya Chen', 'Charles Webb', 'Ada Park', 'Grace Hopper', 'Leo Martins']
const stories = people.map((p, i) => ({ id: String(i), author: p, slides: Array.from({ length: 2 + (i % 2) }, (_, k) => ({ src: demoImage(i + k, 540, 960), alt: `${p} story ${k + 1}`, caption: k === 0 ? `${p.split(' ')[0]} shipped something new` : undefined })) }))
export const styles = { Default: () => <Stories stories={stories} className="w-96" /> }

Source: packages/ui/src/stories/stories.tsx

Catalog

Category
media
Priority
Extra
Primitive
custom