Vertical Story-Style Slider — HTML CSS JS Snippet

Vertical Story-Style Slider · Mobile · Plain HTML, CSS & JS · Live preview

What's included

Features

Segmented top progress bars — one per slide, auto-filling over a fixed duration
Auto-advance on fill completion, exactly matching the native Instagram/Snapchat story pacing
Invisible left/right tap zones spanning the full height, plus Left/Right arrow key support
Accurate scrub state — bars for passed slides show full, upcoming ones show empty, instantly
Bars generated dynamically from slide count — add or remove a slide and the bars follow
Pure CSS width-transition timing, so the fill animation never drops frames or drifts

About this UI Snippet

Vertical Story-Style Slider — Segmented Progress Bars & Tap-to-Advance

Screenshot of the Vertical Story-Style Slider snippet rendered live

Stories replaced the carousel on every social app for one reason: the segmented bar at the top *shows you the pacing* before you even interact — how many slides remain, and roughly how much time is left on this one. This snippet rebuilds that exact mechanic from scratch: one thin bar per slide, the active one fills left-to-right over a fixed duration via a CSS width transition, and finishing a fill auto-advances to the next slide.

A CSS transition doing the timer's job

Instead of animating the fill with requestAnimationFrame on every tick, each active bar's fill gets transition: width 4000ms linear and then its width is set to 100% — the browser handles the actual animation, and a plain setTimeout matching that same duration handles advancing to the next slide. Re-visiting an already-finished slide resets its bar to full instantly (no transition), and resetting to a not-yet-reached slide snaps it back to empty — so scrubbing back and forth always shows an accurate state, not leftover animation frames.

Two invisible tap zones, not visible buttons

The left/right third of the phone frame are full-height, borderless buttons — tapping the right side advances, the left side goes back, exactly like every native stories implementation. Arrow keys do the same on desktop, so the pattern works with a keyboard too, not just a thumb.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain why the active bar's fill has to force a reflow (void fill.offsetWidth) before its transition is re-applied — what happens if that line is removed, and why the browser needs it to notice the width has changed from a previous run. It's also worth asking the assistant to add a hold-to-pause gesture (pausing the fill and timer on pointerdown, resuming on pointerup) since that's the one core stories behavior this snippet doesn't yet implement, or to make it swipeable vertically to dismiss the whole story stack.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a full-screen vertical story slider in plain HTML, CSS, and vanilla JavaScript, modeled on Instagram/Snapchat stories — no library.

Requirements:
- A phone-shaped frame containing several full-bleed slides stacked absolutely on top of each other, with only the active one visible (opacity/z-index controlled by JavaScript, not display:none, so a crossfade is possible).
- A row of thin segmented progress bar elements at the top, one generated dynamically per slide (not hardcoded) — the bar for the active slide fills from empty to full over a fixed duration using a CSS width transition (not a JavaScript animation loop), bars for already-passed slides show fully filled, and bars for upcoming slides show empty.
- When the active slide's bar finishes filling, automatically advance to the next slide and begin filling its bar, unless it is the last slide.
- Two invisible, full-height tap zones on the left and right thirds of the frame (real button elements, not divs) — tapping right advances immediately to the next slide and restarts that slide's timer, tapping left goes back one slide and restarts its timer.
- Left/Right arrow key support that performs the same next/previous action as the tap zones.
- Revisiting a slide (via tap, arrow key, or going back) must correctly reset its progress bar state — no transition should carry over from a previous run, and bars for slides that are not the current one must snap instantly to fully filled or fully empty depending on whether they are before or after the current index.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="vst-phone" id="vstPhone">
  <div class="vst-bars" id="vstBars"></div>
  <div class="vst-header">
    <img class="vst-avatar" src="https://i.pravatar.cc/60?img=32" alt="">
    <div class="vst-who"><strong>fwdtools</strong><span>2h ago</span></div>
  </div>
  <div class="vst-slides" id="vstSlides">
    <div class="vst-slide" style="background:linear-gradient(160deg,#6366f1,#4338ca)"><h2>New tool just dropped 🚀</h2><p>Build sitemaps in one click.</p></div>
    <div class="vst-slide" style="background:linear-gradient(160deg,#ec4899,#9d174d)"><h2>1788+ snippets</h2><p>Copy-paste HTML, CSS &amp; JS, free.</p></div>
    <div class="vst-slide" style="background:linear-gradient(160deg,#0ea5e9,#0369a1)"><h2>Export anywhere</h2><p>React, Vue, Angular &amp; Tailwind.</p></div>
    <div class="vst-slide" style="background:linear-gradient(160deg,#10b981,#047857)"><h2>Swipe to see more</h2><p>Tap the sides to move — try it.</p></div>
  </div>
  <button class="vst-tap vst-tap-left" id="vstPrev" aria-label="Previous story"></button>
  <button class="vst-tap vst-tap-right" id="vstNext" aria-label="Next story"></button>
</div>

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA phone-framed story starts playing automatically — watch the first progress bar fill.
  2. 2
    Tap the right edgeAdvances to the next slide immediately and resets the timer for the new one.
  3. 3
    Tap the left edgeGoes back one slide — its bar refills from the start.
  4. 4
    Wait it outEach slide auto-advances when its bar finishes filling, just like a native story.
  5. 5
    Add a fifth slideAdd one more .vst-slide div — a matching progress bar segment is generated automatically.

Real-world uses

Common Use Cases

App feature announcements
Introduce 3-4 new features in a familiar, tappable format users already know how to navigate.
Onboarding walkthroughs
Segmented pacing shows a new user exactly how many steps remain before they start.
Marketing site "what's new" sections
A story-style embed reads as more current and native than a static changelog list.
Case study or portfolio highlights
Auto-advancing story slides keep a visitor engaged with minimal effort on their part.

Got questions?

Frequently Asked Questions

Change the DURATION constant (in milliseconds) at the top of the JS. It drives both the progress bar's fill transition and the setTimeout that triggers auto-advance, so they always stay in sync.

Tapping either side or pressing an arrow key immediately jumps to a slide and restarts its timer via restart() — so interacting always resets the pacing rather than fighting the running timer.

Listen for pointerdown on the phone frame and clearTimeout(timer) plus pause the active bar's fill (set its width to its current computed value and remove the transition); on pointerup, resume by re-triggering the transition for the remaining width.

Yes — .vst-slide is just a flex container; replace the background gradient with a background-image, or add an <img>/<video> as its first child sized with object-fit: cover.

Yes — Left/Right arrow keys navigate exactly like the tap zones, and the tap zones themselves are real <button> elements with aria-labels.