@reelkit/vue-stories-player

Instagram-style stories player overlay for Vue 3 with cube transitions and auto-advance
766 43
Install
npm install @reelkit/vue-stories-player
Latest Version:0.4.1
Vue:3
License:MIT
Last Updated:Oct 22, 2026
Links: GitHub  ·  npm
Maintainer: konstantin.kai

@reelkit/vue-stories-player

npm Bundle size Statement coverage Star on GitHub

An Instagram-style stories player on a phone: tapping a user's ring opens their stories, a tap moves to the next story, a swipe turns a cube to the next user, a double-tap likes the story with a heart, and closing returns to the rings.

Instagram-style stories player for Vue 3. Full-screen overlay with tap-to-advance navigation, 3D cube transition between users, auto-advance timer, segmented progress bar, and double-tap heart animation. ~7.9 kB gzip.

Live Demo

Installation

npm install @reelkit/vue-stories-player @reelkit/vue lucide-vue-next

Requires Vue 3.3 or later.

Quick Start

<script setup lang="ts">
import { ref } from 'vue';
import {
  StoriesOverlay,
  StoriesRingList,
  type StoriesGroup,
} from '@reelkit/vue-stories-player';
import '@reelkit/vue-stories-player/styles.css';

const groups: StoriesGroup[] = [
  {
    author: { id: 'u1', name: 'Alice', avatar: '/alice.jpg' },
    stories: [
      { id: 's1', mediaType: 'image', src: '/story1.jpg' },
      {
        id: 's2',
        mediaType: 'video',
        src: '/story2.mp4',
        poster: '/poster.jpg',
      },
    ],
  },
  {
    author: { id: 'u2', name: 'Bob', avatar: '/bob.jpg' },
    stories: [{ id: 's3', mediaType: 'image', src: '/story3.jpg' }],
  },
];

const isOpen = ref(false);
const groupIndex = ref(0);

const openGroup = (index: number) => {
  groupIndex.value = index;
  isOpen.value = true;
};
</script>

<template>
  <StoriesRingList :groups="groups" @select="openGroup" />
  <StoriesOverlay
    v-model:is-open="isOpen"
    :groups="groups"
    :initial-group-index="groupIndex"
  />
</template>

Features

  • Tap left/right to navigate stories within a group
  • Swipe left/right with 3D cube transition between users
  • Auto-advance timer with segmented progress bar
  • Tap-and-hold to pause (auto-hides UI)
  • Double-tap heart animation
  • Video stories with autoplay and sound toggle
  • Swipe down to close
  • Keyboard navigation (Arrow keys, Escape)
  • Story ring list with viewed/unviewed gradient
  • Sliding window progress bar for 50+ stories
  • Scoped slots for header, footer, slides and more
  • Desktop navigation arrows
  • Optional Instagram-style desktop carousel of neighbouring groups
  • URL-driven overlay: a shareable link per story, back button closes

API Reference

StoriesOverlay Props

Prop Type Default Description
isOpen boolean required Controls overlay visibility; bind with v-model:is-open
groups StoriesGroup[] required Story groups to display
ariaLabel string Stories player Accessible label of the dialog
initialGroupIndex number 0 Starting group index
initialStoryIndex number resumed or 0 Starting story index; wins over any resume
groupTransition TransitionTransformFn cube Transition between groups
defaultImageDuration number 5000 Image auto-advance duration (ms)
tapZoneSplit number 0.3 Left zone ratio (0-1)
hideUiOnPause boolean true Hide the progress bar and header while paused by a long press
enableKeyboard boolean true Enable keyboard navigation
innerTransitionDuration number 200 Story crossfade duration (ms)
minSegmentWidth number 8 Min progress segment width (px)
desktopLayout 'single' | 'carousel' 'single' 'carousel': neighbouring groups as preview cards beside the story on desktop
chromePlacement 'overlay' | 'group' 'overlay' 'group': each group carries its own progress bar and header, turning with it like Instagram
viewed StoriesViewedStateController — From createStoriesViewedStateController(): resume, recording and muted card rings for watched groups
resumeStoryIndex (groupIndex) => number — Where an unvisited group opens; wins over viewed

Events

Event Payload Description
close — The viewer closed the player
update:is-open boolean Emitted on close — enables v-model:is-open
story-change groupIndex, storyIndex After story navigation
group-change groupIndex After group switch
story-viewed groupIndex, storyIndex When a story is shown
story-complete groupIndex, storyIndex When a story's timer runs out
double-tap groupIndex, storyIndex On double-tap (heart)
pause — On tap-and-hold or the pause button
resume — On release or the play button
api-ready StoriesApi Emitted with the imperative API

The same StoriesApi (nextStory, prevStory, nextGroup, prevGroup, goToGroup, pause, resume) is available through a template ref.

Scoped Slots

Slot Scope
header author, story, storyIndex, isPaused, isMuted, isVideo, groupIndex, isActive, onToggleSound, onTogglePause, onClose
footer author, story, storyIndex
slide story, index, groupIndex, isActive, size, activeGroupIndex, activeStoryIndex, onDurationReady, onReady, onWaiting, onError, onEnded
navigation onPrevStory, onNextStory, onPrevGroup, onNextGroup
progressBar totalStories, activeIndex, progress, group, groupIndex, isActive
loading story, storyIndex, groupIndex
error story, storyIndex, groupIndex
groupPreview group, groupIndex, story, offset, viewedCount, onOpen

A slot that renders nothing falls back to the default.

StoriesUrlOverlay

Takes every StoriesOverlay prop except isOpen, initialGroupIndex and initialStoryIndex, plus a controller from useOverlayUrlState spread with urlIndexTwoAxisKey(...). The ?story=<group>.<story> parameter opens the player, every story change updates it, and one back step closes.

StoriesRingList Props

Prop Type Description
groups StoriesGroup[] Story groups
viewed StoriesViewedStateController Rings follow it by themselves; the same controller the overlay takes
ringSize number Ring diameter (px)

Emits select with the group index when a ring is tapped.

Types

StoriesOverlay and StoriesUrlOverlay are generic over the story shape: extend StoryItem with your own fields and the type is inferred from groups, so passing anything else is a type error. Vue does not carry that type into a scoped slot, so annotate a slot binding with its exported scope type, for example #header="{ story }: HeaderSlotScope<MyStory>".

interface StoryItem {
  id: string;
  mediaType: 'image' | 'video';
  src: string;
  poster?: string;
  duration?: number;
  createdAt?: string | Date;
  /** Media aspect ratio (width / height). */
  aspectRatio?: number;
}

interface AuthorInfo {
  id: string;
  name: string;
  avatar: string;
  verified?: boolean;
}

interface StoriesGroup<T extends StoryItem = StoryItem> {
  author: AuthorInfo;
  stories: T[];
}

Keyboard Shortcuts

Key Action
ArrowLeft Previous story; on a group's first story, the previous group where it was left
ArrowRight Next story; past a group's last story, the next group (the last group closes)
Escape Close overlay

Styling

Class names (.rk-stories-*) and theme tokens (--rk-stories-*) are the same as in @reelkit/react-stories-player, so one theme fits both. Override the tokens at :root (or any ancestor of .rk-stories-overlay) — see the Theming docs for the full token table.

Story rings take their colours from --rk-stories-ring-active-gradient (stories left to watch) and --rk-stories-ring-viewed-color (everything seen). The defaults suit a dark page; on a light one, set them on .rk-stories-ring-list rather than :root, so the rings of the player's own carousel keep theirs.

Documentation

Docs, demos, and customization examples at reelkit.dev/docs/vue-stories-player.

Support

If ReelKit saved you some time, a star on GitHub would mean a lot.

Star on GitHub

License

MIT

Related Packages

@reelkit/vue-reel-player

Full-screen vertical-swipe video/image reel player for Vue 3, inspired by Instag...

1,645 43
@reelkit/vue-lightbox

Full-screen image and video gallery lightbox for Vue 3 with touch gestures, tran...

1,394 43
vue3-touch-events

Simple touch events support for vue.js 3

3,210,829 344
vue2-touch-events

Simple touch events support for vueJS2

1,398,605 540
@reelkit/vue

Vue 3 components and composables for building TikTok/Instagram Reels-style slide...

1,950 43

Version History

Version Released Vue License
0.4.1 >=3.3.0 MIT
0.4.0 >=3.3.0 MIT
0.3.1 >=3.3.0 MIT
0.3.0 >=3.3.0 MIT
0.2.2 >=3.0.0 MIT