← Back to Home

How to Build Instagram Stories in React.js

A Complete Guide to Creating Engaging Story Experiences

By Ankit Jangir | January 25, 2026 | 10 min read

Table of Contents

Introduction

Instagram Stories revolutionized how we share and consume content on social media. The ephemeral, full-screen, and engaging format has become a staple in modern web applications. Whether you're building a social network, a content platform, or an e-commerce site, implementing story features can significantly boost user engagement.

In this comprehensive guide, we'll explore how to build Instagram-style stories in React.js, covering everything from basic implementation to advanced interactive features like polls, quizzes, and custom components.

Why Instagram Stories?

Stories have proven to be incredibly effective for user engagement:

Challenges in Building Stories

Building a production-ready story feature from scratch involves several complex challenges:

1. Media Handling

2. User Interactions

3. Performance Optimization

4. State Management

The Solution: react-instagram-stories

The react-instagram-stories package provides a complete, production-ready solution that handles all these complexities for you. Built with TypeScript and modern React patterns, it offers:

Multiple Content Types

Support for images, videos with audio, text stories, and fully custom React components

High Performance

Only 74.8KB (20KB gzipped) with zero runtime dependencies and intelligent preloading

Full Customization

Style every aspect with CSS, create custom components, and control behavior

TypeScript Support

Complete type definitions included for type-safe development

Accessibility

ARIA labels, keyboard navigation, and screen reader support

Interactive Features

Built-in support for polls, quizzes, countdowns, sliders, and more

Installation

Getting started is simple. Install the package using your preferred package manager:

npm install react-instagram-stories
# or
yarn add react-instagram-stories
# or
pnpm add react-instagram-stories

Note: No additional dependencies required! The package uses the native browser History API for URL-based story navigation, allowing users to share specific stories and maintain browser history without needing react-router-dom.

Quick Start Guide

Here's the minimal setup to get Instagram stories running in your React app:

Step 1: Import Components and Styles

import { Stories, demoUsers } from 'react-instagram-stories';
import 'react-instagram-stories/styles.css';

Step 2: Use the Stories Component

function App() {
  return <Stories users={demoUsers} />;
}

export default App;

That's it! Click on any avatar to open the story viewer. The URL automatically updates to ?user=userId&story=storyId format, enabling sharing and browser history navigation.

You now have a fully functional Instagram stories feature with:

Understanding the Data Structure

The component uses a simple, intuitive data structure. Here's the TypeScript interface:

interface User {
  id: string;
  username: string;
  avatarUrl: string;
  stories: StoryItem[];
  hasUnreadStories?: boolean; // Shows ring around avatar
}

type StoryItemType = 'image' | 'video' | 'text' | 'custom_component';

interface BaseStoryItem {
  id: string;
  type: StoryItemType;
  duration?: number; // Duration in milliseconds
}

Each user has an array of stories, and each story can be one of four types: image, video, text, or custom component.

Four Core Story Types

1. Image Stories

The most common story type. Perfect for photos, graphics, and static visual content:

{
  id: 'image-story-1',
  type: 'image',
  src: 'https://example.com/beautiful-sunset.jpg',
  alt: 'Beautiful sunset over the ocean', // Accessibility
  duration: 5000, // Optional, defaults to 5 seconds
}

2. Video Stories

Video stories with full audio support and intelligent buffering detection:

{
  id: 'video-story-1',
  type: 'video',
  src: 'https://example.com/travel-video.mp4',
  duration: 15000, // Optional, auto-detected from video
}

Key Features:

3. Text Stories

Minimalist stories with text and customizable colors:

{
  id: 'text-story-1',
  type: 'text',
  text: 'Just launched our new feature! 🚀',
  backgroundColor: '#FF6B6B',
  textColor: '#FFFFFF',
  duration: 5000,
}

4. Custom Component Stories

The most powerful feature - add any React component as a story! This opens up unlimited possibilities:

const MyCustomStory: React.FC<StoryItemControls> = ({
  pause,
  resume,
  next,
  prev,
  setDuration
}) => {
  return (
    <div style={{ height: '100%', background: '#667eea', padding: '20px' }}>
      <h1>Custom Interactive Content</h1>
      <button onClick={next}>Next Story</button>
    </div>
  );
};

// Use it in your stories array:
{
  id: 'custom-story-1',
  type: 'custom_component',
  component: MyCustomStory,
  duration: 10000,
}

Building Custom Interactive Stories

Custom components receive five control methods, giving you complete control over the story experience:

Example: Interactive Poll Story

Here's a complete example of building an interactive poll that pauses the timer during interaction:

const PollComponent: React.FC<StoryItemControls> = ({ pause, resume, next }) => {
  const [selected, setSelected] = React.useState<number | null>(null);
  const [votes, setVotes] = React.useState([42, 28, 18, 12]);
  const options = ['React', 'Vue', 'Angular', 'Svelte'];

  // Pause timer when component loads
  React.useEffect(() => {
    pause();
    return () => resume();
  }, [pause, resume]);

  const handleVote = (index: number) => {
    setSelected(index);
    const newVotes = [...votes];
    newVotes[index] += 1;
    setVotes(newVotes);

    // Auto-advance after showing results
    setTimeout(() => {
      resume();
      next();
    }, 2000);
  };

  const total = votes.reduce((a, b) => a + b, 0);

  return (
    <div style={{
      display: 'flex',
      flexDirection: 'column',
      height: '100%',
      background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
      padding: '20px'
    }}>
      <h2 style={{ color: 'white', marginBottom: '20px' }}>
        What's your favorite framework?
      </h2>
      {options.map((option, index) => (
        <button
          key={index}
          onClick={() => handleVote(index)}
          disabled={selected !== null}
          style={{
            margin: '8px 0',
            padding: '15px',
            background: selected === index ? '#4CAF50' : 'rgba(255,255,255,0.2)',
            border: 'none',
            borderRadius: '12px',
          }}
        >
          <div style={{ display: 'flex', justifyContent: 'space-between' }}>
            <span>{option}</span>
            {selected !== null && (
              <span>{((votes[index] / total) * 100).toFixed(0)}%</span>
            )}
          </div>
        </button>
      ))}
    </div>
  );
};

Example: Quiz Story

Create engaging quiz experiences with instant feedback:

const QuizComponent: React.FC<StoryItemControls> = ({ pause, resume, next }) => {
  const [selected, setSelected] = React.useState<number | null>(null);
  const correctAnswer = 2;
  const options = ['Mars', 'Saturn', 'Jupiter', 'Neptune'];

  React.useEffect(() => {
    pause();
    return () => resume();
  }, [pause, resume]);

  const handleAnswer = (index: number) => {
    setSelected(index);
    setTimeout(() => {
      resume();
      next();
    }, 2500);
  };

  return (
    <div style={{
      height: '100%',
      background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
      padding: '20px'
    }}>
      <h2>Which planet is the largest in our solar system?</h2>
      {options.map((option, index) => (
        <button
          key={index}
          onClick={() => handleAnswer(index)}
          disabled={selected !== null}
          style={{
            background: selected === index
              ? (index === correctAnswer ? '#4CAF50' : '#f44336')
              : 'rgba(255,255,255,0.2)'
          }}
        >
          {option}
          {selected !== null && index === correctAnswer && ' ✓'}
        </button>
      ))}
      {selected !== null && (
        <p style={{ marginTop: '20px', fontWeight: 'bold' }}>
          {selected === correctAnswer ? '🎉 Correct!' : '❌ Wrong!'}
        </p>
      )}
    </div>
  );
};

Advanced Features

URL-Based Navigation

Stories are URL-aware using query parameters, allowing users to share specific stories and maintain browser history. When a user opens a story, the URL updates to ?user=userId&story=storyId format, making it easy to share and bookmark. No react-router-dom required!

Keyboard Controls

Touch & Mouse Gestures

Smart Progress Management

The component intelligently manages progress bars:

Performance Optimization

The package is built with performance as a top priority:

Bundle Size

  • Total: 74.8 KB minified
  • Gzipped: ~20 KB
  • ESM: 28.77 KB
  • CJS: 30.44 KB
  • Runtime Dependencies: 0 (React is peer dependency)

Optimization Techniques

The package can smoothly handle 200+ users with 1000+ stories without performance degradation.

Best Practices

1. Optimize Media Assets

2. Set Appropriate Durations

3. Accessibility Considerations

4. User Experience

5. Customization

Override default styles with your brand colors:

/* Custom CSS */
.story-viewer {
  background: rgba(0, 0, 0, 0.95);
}

.story-progress-bar-fill {
  background: linear-gradient(to right, #ff6b6b, #ee5a6f);
}

.avatar {
  width: 80px;
  height: 80px;
  border: 3px solid #E1306C; /* Instagram brand color */
}

Try It Live!

Experience the full demo with all features including polls, quizzes, countdowns, and more.

View Live Demo

View on GitHub

Complete Implementation Example

Here's a complete example showing all story types together:

import React from 'react';
import { Stories } from 'react-instagram-stories';
import type { User } from 'react-instagram-stories';
import 'react-instagram-stories/styles.css';

const myUsers: User[] = [
  {
    id: 'user-1',
    username: 'techexplorer',
    avatarUrl: 'https://i.pravatar.cc/150?img=1',
    hasUnreadStories: true,
    stories: [
      // Image Story
      {
        id: 'story-1',
        type: 'image',
        src: 'https://picsum.photos/1080/1920?random=1',
        alt: 'Beautiful landscape',
        duration: 5000,
      },
      // Video Story
      {
        id: 'story-2',
        type: 'video',
        src: 'https://example.com/video.mp4',
      },
      // Text Story
      {
        id: 'story-3',
        type: 'text',
        text: 'Hello World! 👋',
        backgroundColor: '#FF6B6B',
        textColor: '#FFFFFF',
        duration: 5000,
      },
      // Custom Component Story
      {
        id: 'story-4',
        type: 'custom_component',
        component: PollComponent,
        duration: 15000,
      },
    ],
  },
];

function App() {
  return <Stories users={myUsers} />;
}

export default App;

Click on any avatar to open the story viewer. The URL updates to ?user=user-1&story=story-1 format automatically!

Use Cases

Instagram-style stories aren't just for social media apps. Here are some creative use cases:

E-commerce

Showcase products, flash sales, and customer testimonials in engaging story format

Education

Create interactive lessons, quizzes, and micro-learning experiences

News & Media

Deliver breaking news, photo essays, and multimedia journalism

Marketing

Build campaigns, collect feedback through polls, and drive engagement

SaaS Onboarding

Guide new users through features with interactive walkthroughs

Content Publishing

Share blog highlights, tutorials, and visual content in bite-sized format

API Reference

Stories Component Props

Prop Type Required Description
users User[] Yes Array of user objects with their stories
closeNavigateTo string No Navigation path when viewer closes (default: '/')

Available Exports

// Main component
import { Stories } from 'react-instagram-stories';

// Individual components (for advanced usage)
import { AvatarList, StoryViewer } from 'react-instagram-stories';

// Navigation helpers (no react-router-dom needed!)
import { navigateWithParams, clearQueryParams } from 'react-instagram-stories';

// TypeScript types
import type {
  User,
  StoryItem,
  StoryItemControls,
  StoryItemType,
  ImageStoryItem,
  VideoStoryItem,
  TextStoryItem,
  CustomComponentStoryItem
} from 'react-instagram-stories';

// Demo utilities
import { generateDemoUsers, demoUsers } from 'react-instagram-stories';

// Styles
import 'react-instagram-stories/styles.css';

TypeScript Support

The package is built with TypeScript and provides comprehensive type definitions:

import type {
  User,
  StoryItem,
  StoryItemControls,
  ImageStoryItem,
  VideoStoryItem,
  TextStoryItem,
  CustomComponentStoryItem
} from 'react-instagram-stories';

// Type-safe story creation
const myStory: ImageStoryItem = {
  id: 'story-1',
  type: 'image',
  src: '/photo.jpg',
  alt: 'My photo',
  duration: 5000,
};

Controlled Mode (Without URL Navigation)

If you don't want URL navigation, you can use controlled mode with local state:

import { useState } from 'react';
import { AvatarList, StoryViewer } from 'react-instagram-stories';

function App() {
  const [viewerState, setViewerState] = useState({
    isOpen: false,
    userIndex: 0,
  });

  return (
    <>
      <AvatarList
        users={myUsers}
        onAvatarClick={(index) => setViewerState({
          isOpen: true,
          userIndex: index
        })}
      />
      <StoryViewer
        users={myUsers}
        initialUserIndex={viewerState.userIndex}
        isOpen={viewerState.isOpen}
        onClose={() => setViewerState({
          isOpen: false,
          userIndex: 0
        })}
      />
    </>
  );
}

When the isOpen prop is provided, the StoryViewer enters "controlled mode" and won't read from or update URL query parameters.

Conclusion

Building Instagram-style stories in React doesn't have to be complicated. With the react-instagram-stories package, you get a production-ready solution that handles all the complex aspects like media playback, gestures, keyboard navigation, and performance optimization.

The package's support for custom components means you're not limited to simple image and video stories. You can create interactive polls, quizzes, product showcases, tutorials, and any other creative content you can imagine.

Whether you're building a social network, an e-commerce platform, or an educational app, stories are a proven way to increase engagement and create memorable user experiences.

Ready to Get Started?

Install react-instagram-stories

Star on GitHub ⭐

Additional Resources

About the Author

Ankit Jangir is a software developer passionate about building high-performance React components and open-source tools. Connect on GitHub to see more projects.