DEV Community

Justin Clark
Justin Clark

Posted on

Building Swipeable Views with react-swipeable-views in React

react-swipeable-views is a React component for creating swipeable views with touch and mouse support. It's optimized for performance with lazy loading and provides a small footprint, making it perfect for creating carousels, image galleries, tab panels, and mobile-friendly swipe interfaces. This guide walks through setting up and creating swipeable views using react-swipeable-views with React, from installation to a working implementation.

Simple example

Demo animation

Prerequisites

Before you begin, make sure you have:

  • Node.js version 14.0 or higher installed
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) or create-react-app setup
  • Basic knowledge of React hooks (useState)
  • Familiarity with JavaScript/TypeScript
  • Understanding of touch events and gestures

Installation

Install react-swipeable-views using your preferred package manager:

npm install react-swipeable-views
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add react-swipeable-views
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add react-swipeable-views
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "react-swipeable-views": "^0.14.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

react-swipeable-views requires minimal setup. Import the SwipeableViews component and use it in your application.

First Example / Basic Usage

Let's create a simple swipeable carousel. Create a new file src/SwipeableExample.jsx:

// src/SwipeableExample.jsx
import React from 'react';
import SwipeableViews from 'react-swipeable-views';

const styles = {
  slide: {
    padding: 15,
    minHeight: 100,
    color: '#fff',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    fontSize: '24px'
  },
  slide1: {
    background: '#FEA900',
  },
  slide2: {
    background: '#B3DC4A',
  },
  slide3: {
    background: '#6AC0FF',
  },
};

function SwipeableExample() {
  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>Basic Swipeable Views</h2>
      <SwipeableViews>
        <div style={Object.assign({}, styles.slide, styles.slide1)}>
          Slide 1
        </div>
        <div style={Object.assign({}, styles.slide, styles.slide2)}>
          Slide 2
        </div>
        <div style={Object.assign({}, styles.slide, styles.slide3)}>
          Slide 3
        </div>
      </SwipeableViews>
    </div>
  );
}

export default SwipeableExample;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import SwipeableExample from './SwipeableExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <SwipeableExample />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This creates a basic swipeable carousel with three slides.

Understanding the Basics

react-swipeable-views provides swipeable components:

  • SwipeableViews: Main component for swipeable views
  • Index control: Use index prop to control active slide
  • Change handler: Use onChangeIndex to handle slide changes
  • Touch and mouse: Supports both touch gestures and mouse dragging

Key concepts:

  • Swipeable slides: Each child becomes a swipeable slide
  • Index management: Control which slide is active with index state
  • Change events: Handle slide changes with onChangeIndex
  • Touch support: Works with touch gestures on mobile devices
  • Mouse support: Also works with mouse dragging on desktop

Here's an example with index control:

// src/AdvancedSwipeableExample.jsx
import React, { useState } from 'react';
import SwipeableViews from 'react-swipeable-views';

const styles = {
  slide: {
    padding: 15,
    minHeight: 200,
    color: '#fff',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    fontSize: '24px'
  },
  slide1: { background: '#FEA900' },
  slide2: { background: '#B3DC4A' },
  slide3: { background: '#6AC0FF' },
  slide4: { background: '#FF6B6B' },
};

function AdvancedSwipeableExample() {
  const [index, setIndex] = useState(0);

  const handleChangeIndex = (index) => {
    setIndex(index);
    console.log('Switched to slide:', index);
  };

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>Advanced Swipeable Views</h2>
      <div style={{ marginBottom: '20px', textAlign: 'center' }}>
        <button
          onClick={() => setIndex(Math.max(0, index - 1))}
          disabled={index === 0}
          style={{ padding: '8px 16px', marginRight: '10px' }}
        >
          Previous
        </button>
        <span style={{ margin: '0 10px' }}>Slide {index + 1} of 4</span>
        <button
          onClick={() => setIndex(Math.min(3, index + 1))}
          disabled={index === 3}
          style={{ padding: '8px 16px' }}
        >
          Next
        </button>
      </div>
      <SwipeableViews index={index} onChangeIndex={handleChangeIndex}>
        <div style={Object.assign({}, styles.slide, styles.slide1)}>
          Slide 1
        </div>
        <div style={Object.assign({}, styles.slide, styles.slide2)}>
          Slide 2
        </div>
        <div style={Object.assign({}, styles.slide, styles.slide3)}>
          Slide 3
        </div>
        <div style={Object.assign({}, styles.slide, styles.slide4)}>
          Slide 4
        </div>
      </SwipeableViews>
    </div>
  );
}

export default AdvancedSwipeableExample;
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build an image gallery with swipeable views:

// src/ImageGallery.jsx
import React, { useState } from 'react';
import SwipeableViews from 'react-swipeable-views';

const images = [
  { id: 1, url: 'https://via.placeholder.com/600x400/FEA900/fff?text=Image+1', title: 'Image 1' },
  { id: 2, url: 'https://via.placeholder.com/600x400/B3DC4A/fff?text=Image+2', title: 'Image 2' },
  { id: 3, url: 'https://via.placeholder.com/600x400/6AC0FF/fff?text=Image+3', title: 'Image 3' },
  { id: 4, url: 'https://via.placeholder.com/600x400/FF6B6B/fff?text=Image+4', title: 'Image 4' }
];

function ImageGallery() {
  const [index, setIndex] = useState(0);

  const handleChangeIndex = (index) => {
    setIndex(index);
  };

  return (
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <h2>Image Gallery</h2>
      <div style={{ position: 'relative' }}>
        <SwipeableViews index={index} onChangeIndex={handleChangeIndex}>
          {images.map((image) => (
            <div
              key={image.id}
              style={{
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                height: '400px',
                backgroundColor: '#f0f0f0'
              }}
            >
              <img
                src={image.url}
                alt={image.title}
                style={{
                  maxWidth: '100%',
                  maxHeight: '100%',
                  objectFit: 'contain'
                }}
              />
            </div>
          ))}
        </SwipeableViews>
        <div style={{
          position: 'absolute',
          bottom: '20px',
          left: '50%',
          transform: 'translateX(-50%)',
          display: 'flex',
          gap: '8px'
        }}>
          {images.map((_, i) => (
            <div
              key={i}
              onClick={() => setIndex(i)}
              style={{
                width: '12px',
                height: '12px',
                borderRadius: '50%',
                backgroundColor: index === i ? '#fff' : 'rgba(255,255,255,0.5)',
                cursor: 'pointer',
                transition: 'background-color 0.3s'
              }}
            />
          ))}
        </div>
      </div>
      <div style={{ marginTop: '20px', textAlign: 'center' }}>
        <p>{images[index].title}</p>
        <p>Slide {index + 1} of {images.length}</p>
      </div>
    </div>
  );
}

export default ImageGallery;
Enter fullscreen mode Exit fullscreen mode

Now create a tab panel with swipeable tabs:

// src/SwipeableTabs.jsx
import React, { useState } from 'react';
import SwipeableViews from 'react-swipeable-views';

const tabs = [
  { id: 1, label: 'Tab 1', content: 'Content for Tab 1' },
  { id: 2, label: 'Tab 2', content: 'Content for Tab 2' },
  { id: 3, label: 'Tab 3', content: 'Content for Tab 3' }
];

function SwipeableTabs() {
  const [index, setIndex] = useState(0);

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h2>Swipeable Tabs</h2>
      <div style={{ display: 'flex', borderBottom: '2px solid #ddd', marginBottom: '20px' }}>
        {tabs.map((tab, i) => (
          <button
            key={tab.id}
            onClick={() => setIndex(i)}
            style={{
              flex: 1,
              padding: '10px',
              border: 'none',
              backgroundColor: index === i ? '#007bff' : 'transparent',
              color: index === i ? '#fff' : '#333',
              cursor: 'pointer',
              transition: 'all 0.3s'
            }}
          >
            {tab.label}
          </button>
        ))}
      </div>
      <SwipeableViews index={index} onChangeIndex={setIndex}>
        {tabs.map((tab) => (
          <div
            key={tab.id}
            style={{
              padding: '20px',
              minHeight: '200px',
              backgroundColor: '#f9f9f9',
              borderRadius: '4px'
            }}
          >
            <h3>{tab.label}</h3>
            <p>{tab.content}</p>
          </div>
        ))}
      </SwipeableViews>
    </div>
  );
}

export default SwipeableTabs;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import ImageGallery from './ImageGallery';
import SwipeableTabs from './SwipeableTabs';
import './App.css';

function App() {
  return (
    <div className="App">
      <ImageGallery />
      <SwipeableTabs />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • Image gallery with swipeable navigation
  • Tab panel with swipeable tabs
  • Index control and navigation
  • Touch and mouse support
  • Indicator dots
  • Smooth transitions

Common Issues / Troubleshooting

  1. Swipe not working: Make sure SwipeableViews has children. Check that touch events are not being blocked by other elements.

  2. Index not updating: Ensure onChangeIndex handler is provided and updates state. Check that index prop matches the current slide.

  3. Slides not visible: Verify that slides have proper dimensions. Check CSS for overflow or display issues.

  4. Performance issues: For many slides, consider using lazy loading. Optimize images and content for better performance.

  5. Touch not working on mobile: Check that touch events are enabled. Verify viewport meta tag is set correctly.

  6. Mouse drag not working: Ensure mouse events are not being prevented. Check for CSS that might block pointer events.

Next Steps

Now that you have an understanding of react-swipeable-views:

Summary

You've successfully set up react-swipeable-views in your React application and created swipeable carousels, image galleries, and tab panels with touch and mouse support. react-swipeable-views provides a performant solution for building mobile-friendly swipe interfaces in React applications.

SEO Keywords

react-swipeable-views
react-swipeable-views carousel
React swipeable component
react-swipeable-views installation
React touch swipe
react-swipeable-views tutorial
React swipeable gallery
react-swipeable-views example
React mobile swipe
react-swipeable-views setup
React swipeable tabs
react-swipeable-views getting started
React gesture navigation
react-swipeable-views advanced usage

Top comments (0)