ImagePreview

A beautiful image gallery with zoom and swipe gestures

A full-featured image gallery component with pinch-to-zoom, swipe-to-navigate, and smooth animations. Perfect for displaying photos, products, and media galleries.

Overview

ImagePreview provides a native-like viewing experience for images. It handles gestures automatically and provides a polished, intuitive interface for image browsing.

Use it for:

  • Photo galleries and albums
  • Product image viewers
  • Media previews
  • Portfolio displays
  • Document image viewing

Basic Usage

import { ImagePreview, Button } from 'prizmux'
import { useState } from 'react'

export default function App() {
  const [visible, setVisible] = useState(false)
  
  const images = [
    'https://example.com/photo1.jpg',
    'https://example.com/photo2.jpg',
    'https://example.com/photo3.jpg',
  ]

  return (
    <>
      <Button 
        title="View Gallery" 
        onPress={() => setVisible(true)}
      />
      
      <ImagePreview
        visible={visible}
        images={images}
        onClose={() => setVisible(false)}
      />
    </>
  )
}

With Initial Index

import { ImagePreview } from 'prizmux'

<ImagePreview
  visible={visible}
  images={images}
  initialIndex={2}
  onClose={() => setVisible(false)}
/>

Controlled Gallery

import { ImagePreview, Button } from 'prizmux'
import { View, Text } from 'react-native'
import { useState } from 'react'

export default function ControlledGallery() {
  const [visible, setVisible] = useState(false)
  const [currentIndex, setCurrentIndex] = useState(0)
  
  const images = [
    'https://example.com/photo1.jpg',
    'https://example.com/photo2.jpg',
    'https://example.com/photo3.jpg',
  ]

  return (
    <>
      <Button 
        title="View Gallery" 
        onPress={() => setVisible(true)}
      />
      
      <ImagePreview
        visible={visible}
        images={images}
        initialIndex={currentIndex}
        title={`${currentIndex + 1} of ${images.length}`}
        onClose={() => setVisible(false)}
      />
    </>
  )
}

Product Image Gallery

import { ImagePreview, Button } from 'prizmux'
import { View, Image, ScrollView, Pressable } from 'react-native'
import { useState } from 'react'

export default function ProductGallery({ productImages }) {
  const [visible, setVisible] = useState(false)
  const [selectedIndex, setSelectedIndex] = useState(0)

  return (
    <View style={{ gap: 12 }}>
      {/* Main image */}
      <Pressable onPress={() => setVisible(true)}>
        <Image
          source={{ uri: productImages[selectedIndex] }}
          style={{ width: '100%', height: 300, borderRadius: 12 }}
        />
      </Pressable>
      
      {/* Thumbnails */}
      <ScrollView horizontal showsHorizontalScrollIndicator={false}>
        {productImages.map((image, idx) => (
          <Pressable
            key={idx}
            onPress={() => {
              setSelectedIndex(idx)
              setVisible(true)
            }}
            style={{
              marginRight: 8,
              opacity: selectedIndex === idx ? 1 : 0.6,
            }}
          >
            <Image
              source={{ uri: image }}
              style={{ width: 80, height: 80, borderRadius: 8 }}
            />
          </Pressable>
        ))}
      </ScrollView>
      
      {/* Gallery viewer */}
      <ImagePreview
        visible={visible}
        images={productImages}
        initialIndex={selectedIndex}
        onClose={() => setVisible(false)}
      />
    </View>
  )
}

Custom Icons

import { ImagePreview } from 'prizmux'
import { Text } from 'react-native'

<ImagePreview
  visible={visible}
  images={images}
  onClose={() => setVisible(false)}
  closeIcon={<Text style={{ fontSize: 24 }}>✕</Text>}
  prevIcon={<Text style={{ fontSize: 24 }}>‹</Text>}
  nextIcon={<Text style={{ fontSize: 24 }}>›</Text>}
/>

Props Reference

PropTypeDefaultDescription
visiblebooleanfalseControl gallery visibility
imagesstring | string[]RequiredImage URLs to display
initialIndexnumber0Starting image index
onClose() => voidRequiredCalled when gallery closes
titlestring-Optional header title
closeIconReactNode-Custom close button icon
prevIconReactNode-Custom previous button icon
nextIconReactNode-Custom next button icon

Features

  • ✨ Pinch-to-zoom support
  • 🎯 Swipe gestures for navigation
  • 🎨 Smooth animations
  • 📱 Responsive design
  • 🎭 Customizable icons
  • ♿ Accessibility support

Usage

Basic Gallery

import { ImagePreview } from 'prizmux'

export default function App() {
  const images = [
    { uri: 'https://example.com/photo1.jpg' },
    { uri: 'https://example.com/photo2.jpg' },
    { uri: 'https://example.com/photo3.jpg' },
  ]

  return <ImagePreview images={images} />
}

With Initial Index

<ImagePreview 
  images={productImages}
  initialIndex={2}
/>

Controlled Gallery

import { ImagePreview, Button } from 'prizmux'
import { useState } from 'react'
import { View } from 'react-native'

export default function Gallery() {
  const [currentIndex, setCurrentIndex] = useState(0)

  const images = [
    { uri: 'https://example.com/photo1.jpg' },
    { uri: 'https://example.com/photo2.jpg' },
    { uri: 'https://example.com/photo3.jpg' },
  ]

  return (
    <View style={{ flex: 1 }}>
      <ImagePreview
        images={images}
        initialIndex={currentIndex}
        onIndexChange={setCurrentIndex}
      />
      
      <View style={{ flexDirection: 'row', gap: 8 }}>
        <Button 
          title="Previous"
          disabled={currentIndex === 0}
          onPress={() => setCurrentIndex(currentIndex - 1)}
        />
        <Button 
          title="Next"
          disabled={currentIndex === images.length - 1}
          onPress={() => setCurrentIndex(currentIndex + 1)}
        />
      </View>
    </View>
  )
}

Modal Gallery

import { ImagePreview, Button } from 'prizmux'
import { useState } from 'react'
import { View, Modal } from 'react-native'

export default function ModalGallery() {
  const [visible, setVisible] = useState(false)
  
  const images = [
    { uri: 'https://example.com/photo1.jpg' },
    { uri: 'https://example.com/photo2.jpg' },
  ]

  return (
    <>
      <Button 
        title="View Gallery"
        onPress={() => setVisible(true)}
      />
      
      <Modal
        visible={visible}
        animationType="fade"
      >
        <View style={{ flex: 1, backgroundColor: '#000' }}>
          <ImagePreview
            images={images}
            onClose={() => setVisible(false)}
          />
        </View>
      </Modal>
    </>
  )
}

Product Gallery

import { ImagePreview, Card, Text } from 'prizmux'
import { useState } from 'react'
import { View, Image, TouchableOpacity } from 'react-native'

export default function ProductGallery() {
  const [selectedIndex, setSelectedIndex] = useState(0)
  
  const images = product.images.map(url => ({ uri: url }))

  return (
    <View>
      <ImagePreview
        images={images}
        initialIndex={selectedIndex}
        onIndexChange={setSelectedIndex}
      />
      
      <View style={{ flexDirection: 'row', gap: 8, marginTop: 12 }}>
        {images.map((image, index) => (
          <TouchableOpacity
            key={index}
            onPress={() => setSelectedIndex(index)}
            style={{ 
              borderWidth: index === selectedIndex ? 2 : 0,
              borderRadius: 8,
              overflow: 'hidden'
            }}
          >
            <Image
              source={image}
              style={{ width: 60, height: 60 }}
            />
          </TouchableOpacity>
        ))}
      </View>
    </View>
  )
}

Gestures

  • Swipe left/right — Navigate between images
  • Pinch — Zoom in/out (when enabled)
  • Double tap — Auto-zoom to content
  • Pan while zoomed — Move around zoomed image

Notes

  • Images are cached for smooth scrolling
  • Zoom resets when swiping to next image
  • Supports both local and remote images
  • Page indicator shows current position
  • Optimized for performance with large galleries