Skip to content

magrinj/expo-quick-look

Repository files navigation

@magrinj/expo-quick-look

@magrinj/expo-quick-look

npm version license platforms CI npm downloads docs

A native Expo module for previewing files using QuickLook on iOS and system viewers on Android.

Why this library?

  • Native rendering, not a WebView — Uses iOS QuickLook and Android system viewers. Supports 100+ file formats out of the box with instant rendering, built-in search, and print support.
  • Built for Expo — Zero config, no native linking. Just npx expo install and go. Full TypeScript API with async/await. Works on both New and Old Architecture.
  • More than just preview — Remote file downloads with auth headers, iOS editing/markup, multi-file swipe navigation, thumbnail generation, and lifecycle events (onDismiss, onEditedFile, onSavedEditedCopy). Most alternatives only open a local file in read-only mode.
iOS Android
demo-ios.mp4
demo-android.mp4

Installation

npx expo install @magrinj/expo-quick-look

API

previewFile(options: PreviewFileOptions): Promise<void>

Opens a native file preview.

  • iOS: Presents QLPreviewController modally. Promise resolves when the user dismisses the preview.
  • Android: Launches an Intent chooser with ACTION_VIEW. Promise resolves immediately after launch.
import ExpoQuickLook from '@magrinj/expo-quick-look';

await ExpoQuickLook.previewFile({
  uri: '/path/to/file.pdf',
  // Android only
  chooserTitle: 'Open with',
  // iOS only - 'disabled' | 'createCopy' | 'updateContents'
  editingMode: 'createCopy',
});

Remote files are also supported — the library downloads the file automatically:

await ExpoQuickLook.previewFile({
  uri: 'https://example.com/document.pdf',
});

Authenticated downloads — pass custom headers for protected endpoints:

await ExpoQuickLook.previewFile({
  uri: 'https://api.example.com/documents/123/download',
  requestOptions: {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  },
});

previewFiles(options: PreviewFilesOptions): Promise<void> (iOS only)

Opens a multi-file preview with swipe navigation.

await ExpoQuickLook.previewFiles({
  uris: ['/path/to/file1.pdf', '/path/to/file2.png'],
  initialIndex: 0,
  editingMode: 'disabled',
});

canPreview(uri: string): Promise<boolean>

Checks whether a file can be previewed.

  • iOS: Uses QLPreviewController.canPreview.
  • Android: Checks if any installed app can handle the file's MIME type.
const supported = await ExpoQuickLook.canPreview('/path/to/file.pdf');
// or a remote URL
const supported = await ExpoQuickLook.canPreview('https://example.com/doc.pdf');

For remote URLs, this performs a best-effort check based on the file extension — no download occurs.

generateThumbnail(options: ThumbnailOptions): Promise<ThumbnailResult> (iOS only)

Generates a thumbnail for a file.

const thumbnail = await ExpoQuickLook.generateThumbnail({
  uri: '/path/to/file.pdf',
  size: { width: 200, height: 200 },
  scale: 2, // defaults to device scale
});
// thumbnail.uri - file:// URI to the generated PNG
// thumbnail.width / thumbnail.height - pixel dimensions

Note: generateThumbnail only supports local files. Pass a remote URL and it will throw an error.

Types

type RequestOptions = {
  headers?: Record<string, string>;
};

type PreviewFileOptions = {
  uri: string;
  requestOptions?: RequestOptions;
  chooserTitle?: string;    // Android only
  editingMode?: EditingMode; // iOS only
};

type PreviewFilesOptions = {
  uris: string[];
  requestOptions?: RequestOptions;
  initialIndex?: number;
  editingMode?: EditingMode;
};

type EditingMode = 'disabled' | 'createCopy' | 'updateContents';

type ThumbnailOptions = {
  uri: string;
  size: { width: number; height: number };
  scale?: number;
};

type ThumbnailResult = {
  uri: string;
  width: number;
  height: number;
};

Events

Subscribe using addListener or the useEvent hook from Expo.

Event Platform Payload
onDismiss iOS {}
onEditedFile iOS { filePath: string }
onSavedEditedCopy iOS { originalPath: string, editedPath: string }
const subscription = ExpoQuickLook.addListener('onDismiss', () => {
  console.log('Preview dismissed');
});

// Clean up
subscription.remove();

Platform Differences

Behavior iOS Android
Preview style In-app modal (QuickLook) External app (Intent chooser)
Promise resolution On dismiss Immediately after launch
Multi-file preview Supported Not supported
Editing/markup Supported Not supported
Thumbnails Supported Not supported
Events All events None
Remote URL support Download to temp + preview Download to cache + launch

Example

See the example app for a complete demo.

Support

If you find this library useful, consider supporting its development:

Buy Me A Coffee

License

MIT


Made with ❤️ by Jérémy Magrin

If you find this useful, please star it ⭐ — it helps a lot!

About

Expo module for native file previews — QuickLook on iOS, Intent chooser on Android

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors