React Native course · Module 6: Photos, camera and audio

expo-image-picker - Selecting Images

3 min read ·
In this lesson6

Let users pick images from their gallery or take photos!

Installation

npx expo install expo-image-picker

Permission Configuration (app.json)

{
  "expo": {
    "plugins": [
      [
        "expo-image-picker",
        {
          "photosPermission": "The app requires access to photos",
          "cameraPermission": "The app requires access to the camera"
        }
      ]
    ]
  }
}
import * as ImagePicker from 'expo-image-picker';

function PhotoSelector() {
  const [image, setImage] = useState<string | null>(null);

  const pickImage = async () => {
    // Check permissions
    const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();

    if (status !== 'granted') {
      Alert.alert('Error', 'No gallery permissions');
      return;
    }

    // Open picker
    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ['images'],
      allowsEditing: true,
      aspect: [4, 3],
      quality: 0.8,
    });

    if (!result.canceled && result.assets[0]) {
      setImage(result.assets[0].uri);
    }
  };

  return (
    <View style={styles.container}>
      <Pressable style={styles.button} onPress={pickImage}>
        <Text>Pick a photo</Text>
      </Pressable>

      {image && (
        <Image source={{ uri: image }} style={styles.preview} />
      )}
    </View>
  );
}

Taking a Photo

const takePhoto = async () => {
  const { status } = await ImagePicker.requestCameraPermissionsAsync();

  if (status !== 'granted') {
    Alert.alert('Error', 'No camera permissions');
    return;
  }

  const result = await ImagePicker.launchCameraAsync({
    allowsEditing: true,
    aspect: [1, 1],
    quality: 0.9,
  });

  if (!result.canceled && result.assets[0]) {
    setImage(result.assets[0].uri);
  }
};

ImagePicker Options

const result = await ImagePicker.launchImageLibraryAsync({
  // Media types
  mediaTypes: ['images', 'videos'], // 'images', 'videos', 'livePhotos' (iOS)

  // Editing
  allowsEditing: true,     // Allow cropping
  aspect: [16, 9],         // Aspect ratio (only with allowsEditing)

  // Quality
  quality: 1,              // 0-1 (1 = highest)

  // Multiple images
  allowsMultipleSelection: true,

  // Base64
  base64: false,           // Also return as base64

  // EXIF
  exif: true,              // Photo metadata
});

// Result
if (!result.canceled) {
  result.assets.forEach((asset) => {
    console.log('URI:', asset.uri);
    console.log('Width:', asset.width);
    console.log('Height:', asset.height);
    console.log('Type:', asset.type); // 'image' or 'video'
    console.log('File size:', asset.fileSize);
    console.log('EXIF:', asset.exif);
  });
}

Photo Picker Component

interface ImagePickerButtonProps {
  onImageSelected: (uri: string) => void;
}

function ImagePickerButton({ onImageSelected }: ImagePickerButtonProps) {
  const showOptions = () => {
    Alert.alert(
      'Add photo',
      'Choose source',
      [
        { text: 'Camera', onPress: takePhoto },
        { text: 'Gallery', onPress: pickFromGallery },
        { text: 'Cancel', style: 'cancel' },
      ]
    );
  };

  const takePhoto = async () => {
    const { status } = await ImagePicker.requestCameraPermissionsAsync();
    if (status !== 'granted') return;

    const result = await ImagePicker.launchCameraAsync({
      allowsEditing: true,
      quality: 0.8,
    });

    if (!result.canceled) {
      onImageSelected(result.assets[0].uri);
    }
  };

  const pickFromGallery = async () => {
    const result = await ImagePicker.launchImageLibraryAsync({
      allowsEditing: true,
      quality: 0.8,
    });

    if (!result.canceled) {
      onImageSelected(result.assets[0].uri);
    }
  };

  return (
    <Pressable style={styles.button} onPress={showOptions}>
      <Ionicons name="camera" size={24} />
      <Text>Add photo</Text>
    </Pressable>
  );
}

expo-image-picker is the simplest way to select photos in Expo!

Code for this lesson: App.tsx
import React, { useState } from 'react';
import { View, Text, Pressable, StyleSheet, Alert } from 'react-native';
import { Image } from 'expo-image';
import * as ImagePicker from 'expo-image-picker';

export default function App() {
  const [image, setImage] = useState<string | null>(null);

  const pickFromGallery = async () => {
    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.Images,
      allowsEditing: true,
      quality: 0.8,
    });
    if (!result.canceled) {
      setImage(result.assets[0].uri);
    }
  };

  const takePhoto = async () => {
    const result = await ImagePicker.launchCameraAsync({
      allowsEditing: true,
      quality: 0.8,
    });
    if (!result.canceled) {
      setImage(result.assets[0].uri);
    }
  };

  const showOptions = () => {
    // TODO: call Alert.alert with title 'Add photo' and three buttons:
    //   - { text: 'Camera', onPress: takePhoto }
    //   - { text: 'Gallery', onPress: pickFromGallery }
    //   - { text: 'Cancel', style: 'cancel' }

  };

  return (
    <View style={styles.container}>
      <Pressable style={styles.button} onPress={showOptions}>
        <Text style={styles.buttonText}>Add photo</Text>
      </Pressable>

      {image && <Image source={{ uri: image }} style={styles.preview} />}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center',
    backgroundColor: '#1a5276',
  },
  button: {
    backgroundColor: '#2980b9',
    padding: 14,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: { color: '#fff', fontSize: 16, fontWeight: '600' },
  preview: { width: '100%', height: 250, borderRadius: 12, marginTop: 20 },
});

Docs entries used in this lesson

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. Which function opens the photo gallery?

  2. 2. Which option allows selecting multiple photos?

Hands-on tasks in the game

  • Click in order

    Click the image picker configuration elements that allow picking only images:

  • Code editor

    Complete the code with Alert and ImagePicker.

Useful articles