# React Native document picker & viewer > Modules for picking and previewing documents in React Native applications This file contains all documentation content in a single document following the llmstxt.org standard. ## document-picker API ## Type Aliases ### BookmarkingResponse > **BookmarkingResponse** = \{ `bookmark`: `string`; `bookmarkStatus`: `"success"`; \} \| \{ `bookmarkError`: `string`; `bookmarkStatus`: `"error"`; \} If you've requested long-term access to a directory or file, this object is returned in the response. In order to access the same directory or file in the future, you must store the `bookmark` opaque string, and then pass it to the document viewer if you want to preview the file. See the Document viewer sources on how to retrieve the file from the bookmark, if you need to do that (advanced use case). *** ### FileToCopy > **FileToCopy** = \{ `convertVirtualFileToType?`: `string`; `fileName`: `string`; `uri`: `string`; \} Parameter of [keepLocalCopy](#keeplocalcopy). Object type representing the file(s) whose copy should be kept in the app's storage. #### Properties ##### convertVirtualFileToType? > `optional` **convertVirtualFileToType**: `string` Only for Android virtual files: the type of the file to export to. For example, `application/pdf` or `text/plain`. Use one of the values from `convertibleToMimeTypes` from the response of the `pick()` method: [DocumentPickerResponse](#documentpickerresponse). ##### fileName > **fileName**: `string` The name of the resulting file, with the file extension. You can use the `name` field from the response of the `pick()` method. Example: someFile.pdf ##### uri > **uri**: `string` The uri to keep a local copy of. This would be a `content://` uri (Android), or a `file://` uri (iOS) that the user has previously picked. *** ### IsKnownTypeOptions > **IsKnownTypeOptions** = \{ `kind`: `"UTType"` \| `"mimeType"` \| `"extension"`; `value`: `string`; \} #### Properties ##### kind > **kind**: `"UTType"` \| `"mimeType"` \| `"extension"` the kind of value you're passing ##### value > **value**: `string` the value you're checking, for example: `application/pdf`, `com.adobe.pdf`, `pdf` *** ### IsKnownTypeResponse > **IsKnownTypeResponse** = \{ `isKnown`: `boolean`; `mimeType`: `string` \| `null`; `preferredFilenameExtension`: `string` \| `null`; `UTType`: `string` \| `null`; \} The result of calling [isKnownType](#isknowntype) #### Properties ##### isKnown > **isKnown**: `boolean` On iOS, this is true if the type is known to the device. That means it can be used with the document picker to filter what files can be picked. On Android, this is true if the internal mime type database contains the given value. ##### mimeType > **mimeType**: `string` \| `null` the mime type for the given value, if any ##### preferredFilenameExtension > **preferredFilenameExtension**: `string` \| `null` the preferred filename extension for the given value, if any ##### UTType > **UTType**: `string` \| `null` the UTType identifier for the given value, if any *** ### KeepLocalCopyOptions > **KeepLocalCopyOptions** = \{ `destination`: `"cachesDirectory"` \| `"documentDirectory"`; `files`: [`NonEmptyArray`](#nonemptyarray)\<[`FileToCopy`](#filetocopy)\>; \} options for [keepLocalCopy](#keeplocalcopy) #### Properties ##### destination > **destination**: `"cachesDirectory"` \| `"documentDirectory"` ##### files > **files**: [`NonEmptyArray`](#nonemptyarray)\<[`FileToCopy`](#filetocopy)\> *** ### KeepLocalCopyResponse > **KeepLocalCopyResponse** = [`NonEmptyArray`](#nonemptyarray)\<[`LocalCopyResponse`](#localcopyresponse)\> Result of the call to [keepLocalCopy](#keeplocalcopy). Please note the promise always resolves, even if there was an error processing any uri(s) (as indicated by the `status` field, and `copyError` field). *** ### LocalCopyResponse > **LocalCopyResponse** = \{ `localUri`: `string`; `sourceUri`: `string`; `status`: `"success"`; \} \| \{ `copyError`: `string`; `sourceUri`: `string`; `status`: `"error"`; \} Indicates, for each Uri that was passed to [keepLocalCopy](#keeplocalcopy), whether the local copy was successfully created or not. If the copy was successful, the status field is `success` and `localUri` contains the local Uri. If the copy was not successful, the status field is `error` and `copyError` field contains the error message. *** ### NonEmptyArray > **NonEmptyArray**\<`T`\> = \[`T`, `...T[]`\] #### Type Parameters | Type Parameter | | ------ | | `T` | *** ### PredefinedFileTypes > **PredefinedFileTypes** = `Flatten`\<`AllMimeTypes`\> \| `AllAppleUTIs` You'd rarely use this type directly. It represents the predefined file types which are exported as `types` and can be used to limit the kinds of files that can be picked. #### Example ```ts import { pick, types, } from '@react-native-documents/picker' // ... const result = await pick({ type: [types.pdf, types.docx], }) ``` *** ### PresentationStyle > **PresentationStyle** = `"fullScreen"` \| `"pageSheet"` \| `"formSheet"` \| `"overFullScreen"` \| `undefined` iOS only. Configure the presentation style of the picker. *** ### ReleaseLongTermAccessResult > **ReleaseLongTermAccessResult** = (\{ `status`: `"success"`; `uri`: `string`; \} \| \{ `errorMessage`: `string`; `status`: `"error"`; `uri`: `string`; \})[] For each uri whose release was requested, the result contains an object with the uri and a status. *** ### TransitionStyle > **TransitionStyle** = `"coverVertical"` \| `"flipHorizontal"` \| `"crossDissolve"` \| `"partialCurl"` \| `undefined` iOS only. Configure the transition style of the picker. ## Variables ### errorCodes > `const` **errorCodes**: `Readonly`\<\{ `IN_PROGRESS`: `"ASYNC_OP_IN_PROGRESS"`; `NULL_PRESENTER`: `"NULL_PRESENTER"`; `OPERATION_CANCELED`: `"OPERATION_CANCELED"`; `UNABLE_TO_OPEN_FILE_TYPE`: `"UNABLE_TO_OPEN_FILE_TYPE"`; \}\> Error codes that can be returned by the module, and are available on the `code` property of the error. #### Example ```ts const handleError = (err: unknown) => { if (isErrorWithCode(err)) { switch (err.code) { case errorCodes.IN_PROGRESS: ... break case errorCodes.UNABLE_TO_OPEN_FILE_TYPE: ... break case errorCodes.OPERATION_CANCELED: // ignore break default: console.error(err) } } else { console.error(err) } } ``` ## Functions ### isErrorWithCode() > **isErrorWithCode**(`error`: `any`): `error is NativeModuleError` TypeScript helper to check if an object has the `code` property. This is used to avoid `as` casting when you access the `code` property on errors returned by the module. #### Parameters | Parameter | Type | | ------ | ------ | | `error` | `any` | #### Returns `error is NativeModuleError` *** ### releaseLongTermAccess() > **releaseLongTermAccess**(`uris`: `string`[]): `Promise`\<[`ReleaseLongTermAccessResult`](#releaselongtermaccessresult)\> Android only - Releases long-term access to the given URIs. There's no need to call this method on iOS - there's no iOS equivalent. See [Android documentation](https://developer.android.com/reference/android/content/ContentResolver#releasePersistableUriPermission(android.net.Uri,%20int)) for more information. #### Parameters | Parameter | Type | | ------ | ------ | | `uris` | `string`[] | #### Returns `Promise`\<[`ReleaseLongTermAccessResult`](#releaselongtermaccessresult)\> *** ### releaseSecureAccess() > **releaseSecureAccess**(`uris`: `string`[]): `Promise`\<`null`\> iOS only - Releases (stops) secure access to the given URIs. Use with URIs obtained with Open mode or with the Directory Picker. See [iOS documentation](https://developer.apple.com/documentation/foundation/nsurl/1413736-stopaccessingsecurityscopedresou) for more information. There's no need to call this method on Android - there's no equivalent method on Android. #### Parameters | Parameter | Type | | ------ | ------ | | `uris` | `string`[] | #### Returns `Promise`\<`null`\> ## DocumentPicker ### isKnownType() > **isKnownType**(`options`: [`IsKnownTypeOptions`](#isknowntypeoptions)): [`IsKnownTypeResponse`](#isknowntyperesponse) Checks if the given value (which can be a file extension, UTType identifier or mime) is known to the system. Also returns the mime type which you can use to filter files on Android. #### Parameters | Parameter | Type | | ------ | ------ | | `options` | [`IsKnownTypeOptions`](#isknowntypeoptions) | #### Returns [`IsKnownTypeResponse`](#isknowntyperesponse) *** ### keepLocalCopy() > **keepLocalCopy**(`options`: [`KeepLocalCopyOptions`](#keeplocalcopyoptions)): `Promise`\<\[[`LocalCopyResponse`](#localcopyresponse), `...LocalCopyResponse[]`\]\> Makes the file available in the app's storage. The behavior is different on iOS and Android, and for simple use cases (such as uploading file to remote server), you may not need to call this method at all. On Android, it can be used to "convert" a `content://` Uri into a local file. It also "exports" virtual files (such as Google docs or sheets) into local files. However, note that for some use cases, such as uploading the picked file to a server, you may not need to call `keepLocalCopy` at all. React Native's `fetch` can handle `content://` uris. #### Parameters | Parameter | Type | | ------ | ------ | | `options` | [`KeepLocalCopyOptions`](#keeplocalcopyoptions) | #### Returns `Promise`\<\[[`LocalCopyResponse`](#localcopyresponse), `...LocalCopyResponse[]`\]\> *** ### pick() > **pick**\<`O`\>(`options?`: `O`): `PickResponse`\<`O`\> The method for picking a file, both for `import` and `open` modes. For result types, see [DocumentPickerResponse](#documentpickerresponse) or [DocumentPickerResponseOpenLongTerm](#documentpickerresponseopenlongterm). For options, see [DocumentPickerOptionsImport](#documentpickeroptionsimport), [DocumentPickerOptionsOpenOnce](#documentpickeroptionsopenonce) or [DocumentPickerOptionsOpenLongTerm](#documentpickeroptionsopenlongterm). #### Type Parameters | Type Parameter | | ------ | | `O` *extends* `DocumentPickerOptions` | #### Parameters | Parameter | Type | | ------ | ------ | | `options?` | `O` | #### Returns `PickResponse`\<`O`\> *** ### pickDirectory() > **pickDirectory**\<`O`\>(`options?`: `O`): [`PickDirectoryResponse`](#pickdirectoryresponse)\<`O`\> Opens a directory picker. #### Type Parameters | Type Parameter | | ------ | | `O` *extends* [`DirectoryPickerOptions`](#directorypickeroptions) | #### Parameters | Parameter | Type | | ------ | ------ | | `options?` | `O` | #### Returns [`PickDirectoryResponse`](#pickdirectoryresponse)\<`O`\> *** ### saveDocuments() > **saveDocuments**(`options`: [`SaveDocumentsOptions`](#savedocumentsoptions)): `Promise`\<\[[`SaveDocumentsResponse`](#savedocumentsresponse), `...SaveDocumentsResponse[]`\]\> The method for opening a "save as" dialog and saving source file(s) to a new location. On Android, only one file can be saved at a time. #### Parameters | Parameter | Type | | ------ | ------ | | `options` | [`SaveDocumentsOptions`](#savedocumentsoptions) | #### Returns `Promise`\<\[[`SaveDocumentsResponse`](#savedocumentsresponse), `...SaveDocumentsResponse[]`\]\> ## pick() types ### DocumentPickerOptionsBase > **DocumentPickerOptionsBase** = \{ `allowMultiSelection?`: `boolean`; `allowVirtualFiles?`: `boolean`; `presentationStyle?`: [`PresentationStyle`](#presentationstyle-2); `transitionStyle?`: [`TransitionStyle`](#transitionstyle-2); `type?`: `string` \| [`PredefinedFileTypes`](#predefinedfiletypes) \| ([`PredefinedFileTypes`](#predefinedfiletypes) \| `string`)[]; \} Base options object for the document picker. You'd rarely use this type directly, but instead use one of [DocumentPickerOptionsImport](#documentpickeroptionsimport), [DocumentPickerOptionsOpenOnce](#documentpickeroptionsopenonce) or [DocumentPickerOptionsOpenLongTerm](#documentpickeroptionsopenlongterm) which extend this type #### Properties ##### allowMultiSelection? > `optional` **allowMultiSelection**: `boolean` Whether to allow multiple files to be picked. False by default. ##### allowVirtualFiles? > `optional` **allowVirtualFiles**: `boolean` Android only - Whether to allow virtual files (such as Google docs or sheets) to be picked. False by default. ##### presentationStyle? > `optional` **presentationStyle**: [`PresentationStyle`](#presentationstyle-2) iOS only - Controls how the picker is presented, e.g. on an iPad you may want to present it fullscreen. Defaults to `pageSheet`. ##### transitionStyle? > `optional` **transitionStyle**: [`TransitionStyle`](#transitionstyle-2) iOS only - Configures the transition style of the picker. Defaults to coverVertical, when the picker is presented, its view slides up from the bottom of the screen. ##### type? > `optional` **type**: `string` \| [`PredefinedFileTypes`](#predefinedfiletypes) \| ([`PredefinedFileTypes`](#predefinedfiletypes) \| `string`)[] Specify file type(s) that you want to pick. Use `types` for some predefined values. *** ### DocumentPickerOptionsImport > **DocumentPickerOptionsImport** = [`DocumentPickerOptionsBase`](#documentpickeroptionsbase) & \{ `mode?`: `"import"`; `requestLongTermAccess?`: `never`; \} Present the document picker in import mode. #### Type Declaration | Name | Type | | ------ | ------ | | `mode?` | `"import"` | | `requestLongTermAccess?` | `never` | *** ### DocumentPickerOptionsOpenLongTerm > **DocumentPickerOptionsOpenLongTerm** = [`DocumentPickerOptionsBase`](#documentpickeroptionsbase) & \{ `mode`: `"open"`; `requestLongTermAccess`: `true`; \} Present the document picker in open mode, with long-term permissions to access the opened file. #### Type Declaration | Name | Type | | ------ | ------ | | `mode` | `"open"` | | `requestLongTermAccess` | `true` | *** ### DocumentPickerOptionsOpenOnce > **DocumentPickerOptionsOpenOnce** = [`DocumentPickerOptionsBase`](#documentpickeroptionsbase) & \{ `mode`: `"open"`; `requestLongTermAccess?`: `false`; \} Present the document picker in open mode, with permissions to access the file for a limited time (until the app terminates). #### Type Declaration | Name | Type | | ------ | ------ | | `mode` | `"open"` | | `requestLongTermAccess?` | `false` | *** ### DocumentPickerResponse > **DocumentPickerResponse** = \{ `convertibleToMimeTypes`: [`VirtualFileMeta`](#virtualfilemeta)[] \| `null`; `error`: `string` \| `null`; `hasRequestedType`: `boolean`; `isVirtual`: `boolean` \| `null`; `name`: `string` \| `null`; `nativeType`: `string` \| `null`; `size`: `number` \| `null`; `type`: `string` \| `null`; `uri`: `string`; \} #### Properties ##### convertibleToMimeTypes > **convertibleToMimeTypes**: [`VirtualFileMeta`](#virtualfilemeta)[] \| `null` Android: The target types the virtual file can be converted to. Useful for [keepLocalCopy](#keeplocalcopy). This field is only present if `isVirtual` is true, and only on Android 7.0+. Always `null` on iOS. ##### error > **error**: `string` \| `null` Error in case the file metadata could not be obtained. ##### hasRequestedType > **hasRequestedType**: `boolean` Android: Some document providers on Android (especially those popular in Asia, it seems) do not respect the request for limiting selectable file types. `hasRequestedType` is false if the user picked a file that does not have one of the requested types. You need to do your own post-processing and display an error to the user if this is important to your app. Always `true` on iOS. ##### isVirtual > **isVirtual**: `boolean` \| `null` Android: whether the file is a virtual file (such as Google docs or sheets). This is `null` on pre-Android 7.0 devices. On iOS, it's always `false`. ##### name > **name**: `string` \| `null` The name of the picked file, including the extension. It's very unlikely that it'd be `null` but in theory, it can happen. ##### nativeType > **nativeType**: `string` \| `null` The "native" type of the picked file: on Android, this is the MIME type. On iOS, it is the UTType identifier. ##### size > **size**: `number` \| `null` The size of the picked file in bytes. ##### type > **type**: `string` \| `null` The MIME type of the picked file. ##### uri > **uri**: `string` The URI of the picked file. This is a percent-encoded `content://` uri (Android), or a `file://` uri (iOS). *** ### DocumentPickerResponseOpenLongTerm > **DocumentPickerResponseOpenLongTerm** = [`DocumentPickerResponse`](#documentpickerresponse) & [`BookmarkingResponse`](#bookmarkingresponse) The result of calling [pick](#pick) with `mode: 'open'` and `requestLongTermAccess: true` *** ### VirtualFileMeta > **VirtualFileMeta** = \{ `extension`: `string` \| `null`; `mimeType`: `string`; \} #### Properties ##### extension > **extension**: `string` \| `null` The registered extension for the given MIME type. Note that some MIME types map to multiple extensions. This call returns the most common extension for the given MIME type. Example: `pdf` ##### mimeType > **mimeType**: `string` The MIME type of the file. This is necessary to export the virtual file to a local file. Example: `application/pdf` ## pickDirectory() types ### DirectoryPickerOptions > **DirectoryPickerOptions** = [`DirectoryPickerOptionsBase`](#directorypickeroptionsbase) & \{ `requestLongTermAccess`: `boolean`; \} Options for [pickDirectory](#pickdirectory). #### Type Declaration | Name | Type | | ------ | ------ | | `requestLongTermAccess` | `boolean` | *** ### DirectoryPickerOptionsBase > **DirectoryPickerOptionsBase** = \{ `presentationStyle?`: [`PresentationStyle`](#presentationstyle-2); `transitionStyle?`: [`TransitionStyle`](#transitionstyle-2); \} Base options object for the directory picker. They only slightly influence the appearance of the picker modal on iOS. You'd rarely use this type directly, but instead use [DirectoryPickerOptions](#directorypickeroptions) which extend this type #### Properties ##### presentationStyle? > `optional` **presentationStyle**: [`PresentationStyle`](#presentationstyle-2) iOS only - Controls how the picker is presented, e.g. on an iPad you may want to present it fullscreen. Defaults to `pageSheet`. ##### transitionStyle? > `optional` **transitionStyle**: [`TransitionStyle`](#transitionstyle-2) iOS only - Configures the transition style of the picker. Defaults to coverVertical, when the picker is presented, its view slides up from the bottom of the screen. *** ### DirectoryPickerResponse > **DirectoryPickerResponse** = \{ `uri`: `string`; \} This object represents the response from the directory picker, when long-term access was not requested. #### Properties ##### uri > **uri**: `string` The (percent-encoded) directory selected by user. *** ### DirectoryPickerResponseLongTerm > **DirectoryPickerResponseLongTerm** = [`DirectoryPickerResponse`](#directorypickerresponse) & [`BookmarkingResponse`](#bookmarkingresponse) This object represents the response from the directory picker, when long-term access was requested. *** ### PickDirectoryResponse > **PickDirectoryResponse**\<`O`\> = `Promise`\<`O` *extends* `DirectoryPickerOptionsLongTerm` ? [`DirectoryPickerResponseLongTerm`](#directorypickerresponselongterm) : [`DirectoryPickerResponse`](#directorypickerresponse)\> You likely won't use this type directly, but instead use [DirectoryPickerResponse](#directorypickerresponse) or [DirectoryPickerResponseLongTerm](#directorypickerresponselongterm). #### Type Parameters | Type Parameter | | ------ | | `O` *extends* [`DirectoryPickerOptions`](#directorypickeroptions) | ## saveDocuments() types ### SaveDocumentsOptions > **SaveDocumentsOptions** = \{ `copy?`: `boolean`; `fileName?`: `string`; `mimeType?`: `string`; `sourceUris`: `string`[]; \} Options object for the [saveDocuments](#savedocuments) method. `sourceUris` is the only required field. #### Properties ##### copy? > `optional` **copy**: `boolean` iOS-only: Whether to copy the file to a new location, or move it (default). On Android, file is always copied. ##### fileName? > `optional` **fileName**: `string` Android-only: The suggested title of the file to be stored, which will be pre-filled in the UI. On iOS, the target name is taken from the source uri, and is changeable only when exactly one file is being saved. ##### mimeType? > `optional` **mimeType**: `string` Android-only: The MIME type of the file to be stored. It is recommended to provide this value, otherwise the system tries to infer it from the sourceUri using ContentResolver. ##### sourceUris > **sourceUris**: `string`[] The source URIs of the files to save, percentage-encoded. Android only allows to save one file at a time, iOS allows multiple. *** ### SaveDocumentsResponse > **SaveDocumentsResponse** = \{ `error`: `string` \| `null`; `name`: `string` \| `null`; `uri`: `string`; \} The result of calling [saveDocuments](#savedocuments). It is very unlikely that the metadata fields would be `null`, but in theory, it can happen. #### Properties ##### error > **error**: `string` \| `null` Error in case the file could not be written or some metadata could not be obtained. ##### name > **name**: `string` \| `null` The name of the file that user entered, including extension. ##### uri > **uri**: `string` The target URI - the one user saved to. This is a percent-encoded `content://` uri (Android), or a `file://` uri (iOS). --- ## document-viewer API ## Type Aliases ### BaseOptions > **BaseOptions** = \{ `androidApplicationId?`: `string`; `grantPermissions?`: `"read"` \| `"write"`; `headerTitle?`: `string`; `mimeType?`: `string`; `presentationStyle?`: [`PresentationStyle`](#presentationstyle-1); \} #### Properties ##### androidApplicationId? > `optional` **androidApplicationId**: `string` Android only - Optional, only provide a value if calling [viewDocument](#viewdocument) rejects with `IllegalArgumentException`. Represents the unique identifier for an Android application. Defaults to application package name, which usually is the same as the application id. ##### grantPermissions? > `optional` **grantPermissions**: `"read"` \| `"write"` Android only: The type of permission to grant to the receiving app that will open the document. This only has an effect if you're viewing a file that lives in the app's sandboxed storage. ##### headerTitle? > `optional` **headerTitle**: `string` iOS only: The title to display in the header of the document viewer. ###### Default ```ts the file name. ``` ##### mimeType? > `optional` **mimeType**: `string` Optional, but strongly recommended: the mimetype of the document. This helps the Android OS to find the right app(s) to open the document. ##### presentationStyle? > `optional` **presentationStyle**: [`PresentationStyle`](#presentationstyle-1) iOS only - Controls how the picker is presented, e.g. on an iPad you may want to present it fullscreen. ###### Default `pageSheet`. *** ### OptionsViewBookmark > **OptionsViewBookmark** = [`BaseOptions`](#baseoptions) & \{ `bookmark`: `string`; \} BaseOptions with the bookmark data from the DocumentPicker module. Obtain the bookmark using the "open" mode, with `requestLongTermAccess` flag set to true. A bookmark enables long-term access to a file. #### Type Declaration | Name | Type | Description | | ------ | ------ | ------ | | `bookmark` | `string` | bookmark data from the DocumentPicker module. Obtain it using the "open" mode, with `requestLongTermAccess` flag set to true. A bookmark allows a long-term permission to access a file. | *** ### OptionsViewUri > **OptionsViewUri** = [`BaseOptions`](#baseoptions) & \{ `uri`: `string`; \} BaseOptions with the uri of the document to view #### Type Declaration | Name | Type | Description | | ------ | ------ | ------ | | `uri` | `string` | The uri of the document to view | *** ### PresentationStyle > **PresentationStyle** = `"fullScreen"` \| `"pageSheet"` \| `"formSheet"` \| `"overFullScreen"` \| `undefined` iOS only. Configure the presentation style of the picker. *** ### ViewDocumentOptions > **ViewDocumentOptions** = [`OptionsViewBookmark`](#optionsviewbookmark) \| [`OptionsViewUri`](#optionsviewuri) options for viewing a document If you're trying to open a file that you have long-term permission to access, you should use the `bookmark` option (provided by the DocumentPicker module). ## Variables ### errorCodes > `const` **errorCodes**: `Readonly`\<\{ `NULL_PRESENTER`: `"NULL_PRESENTER"`; `UNABLE_TO_OPEN_FILE_TYPE`: `"UNABLE_TO_OPEN_FILE_TYPE"`; \}\> ## Functions ### isErrorWithCode() > **isErrorWithCode**(`error`: `unknown`): `error is NativeModuleError` TypeScript helper to check if an object has the `code` property. This is used to avoid `as` casting when you access the `code` property on errors returned by the module. #### Parameters | Parameter | Type | | ------ | ------ | | `error` | `unknown` | #### Returns `error is NativeModuleError` *** ### viewDocument() > **viewDocument**(`data`: [`ViewDocumentOptions`](#viewdocumentoptions)): `Promise`\<`null`\> #### Parameters | Parameter | Type | | ------ | ------ | | `data` | [`ViewDocumentOptions`](#viewdocumentoptions) | #### Returns `Promise`\<`null`\> --- ## Installation Depending on what module you need, install one or both of the packages: ```bash yarn add @react-native-documents/picker ``` ```bash yarn add @react-native-documents/viewer ``` ## Setting up The packages are designed to support last 3 stable versions of RN. However, they very likely work with RN 0.76 and up. ### Expo :::info These packages cannot be used in ["Expo Go"](https://docs.expo.dev/workflow/overview/#expo-go-an-optional-tool-for-learning) because they include custom native code. However, you can add custom native code to an Expo app through a [development build](https://docs.expo.dev/workflow/overview/#development-builds). That is the officially recommended approach for building Expo apps. See the commands below to do this. ::: ```bash # install the package first # Build the app locally expo prebuild --clean expo run:ios expo run:android ``` ### React Native Install the package and then run `pod install` from the ios directory. Then rebuild your project with Xcode. If you're using the [New Architecture](https://reactnative.dev/docs/new-architecture-intro), it's strongly recommended to use the latest stable release of RN. --- ## Error handling This page describes the case when calling any of the modules' method rejects. Keep in mind other errors can also happen in `pick` ([see `error` and `hasRequestedType`](../doc-picker-api#documentpickerresponse)) and `keepLocalCopy` ([see `copyError`](../doc-picker-api#localcopyresponse)). ### Error codes Both `picker` and `viewer` expose the `errorCodes` object which contains an object of possible error codes that can be returned by the native module. Error codes are useful when determining which kind of error has occurred during the picking or viewing process. | Error Code Key | Description | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `IN_PROGRESS` | This is rather a warning, that happens when you invoke an operation (e.g. `pick`) while a previous one has not finished yet. For example: if you call `pick()` quickly twice in a row, 2 calls to `pick()` in the native module will be done. The first call will open the native document picker and user action will be expected. The promise from the second call to `pick` will be rejected with this error. Later, the first promise will resolve (or reject) with the actual files that the user has selected. Only one document picker window will be presented to the user. The reason the module explicitly rejects "duplicated" calls is to avoid memory leaks and to inform you that something probably isn't done right. | | `UNABLE_TO_OPEN_FILE_TYPE` | When you try to use the picker or viewer using a configuration that system cannot comply with. On Android, this corresponds to [ActivityNotFoundException](https://developer.android.com/reference/android/content/ActivityNotFoundException). On iOS, this only happens in the Viewer module when you attempt to preview a file that's not supported by the [QuickLook framework](https://developer.apple.com/documentation/quicklook/qlpreviewcontroller/1617016-canpreviewitem?language=objc). | | `OPERATION_CANCELED` | When user cancels the operation | :::note In a future release, `OPERATION_CANCELED` will be replaced with a more streamlined cancellation handling. I'm keeping it now to make [migration](migration.md) easier. ::: ```ts title="error-handling.ts" import { errorCodes } from '@react-native-documents/picker' // or import { errorCodes } from '@react-native-documents/viewer' const handleError = (err: unknown) => { if (isErrorWithCode(err)) { switch (err.code) { case errorCodes.IN_PROGRESS: console.warn('user attempted to present a picker, but a previous one was already presented') break case errorCodes.UNABLE_TO_OPEN_FILE_TYPE: setError('unable to open file type') break case errorCodes.OPERATION_CANCELED: // ignore break default: setError(String(err)) console.error(err) } } else { setError(String(err)) } } ``` ### `isErrorWithCode(value)` TypeScript helper to check if the passed parameter is an instance of `Error` which has the `code` property. All errors thrown by the picker and viewer native modules have the `code` property, which contains a value from [`errorCodes`](#error-codes) or some other string for the less-usual errors. `isErrorWithCode` can be used to avoid `as` casting when you want to access the `code` property on errors returned by the module. ```ts import { pick, isErrorWithCode } from '@react-native-documents/picker' try { const [pickResult] = await pick() // do something with pickResult } catch (error) { if (isErrorWithCode(error)) { // here you can safely read `error.code` and TypeScript will know that it has a value } else { // this error does not have a `code`, and does not come from the native module } } ``` --- ## Introduction Welcome to the docs for `@react-native-documents/picker` and `@react-native-documents/viewer` packages. These packages provide a way to pick, save ('save as' dialog) documents and view documents on the device's file system or remote locations. Originally, there was only `react-native-document-picker` ([see here](https://github.com/react-native-documents/document-picker/tree/master)), but the package was fully rewritten and published in 1/2025 and the `viewer` package was added. ## What's new in the full rewrite? There's the improved (list of changes below) picker package (called `@react-native-documents/picker`) with api that's very similar to the [original](https://github.com/react-native-documents/document-picker/tree/master). Secondly, there's the completely new `@react-native-documents/viewer` package which is designed to work well together with `picker`. ### TypeScript - improved type definitions that make use of [Discriminated Unions](https://basarat.gitbook.io/typescript/type-system/discriminated-unions) and other goodies so that you don't try to read fields that are not there, and nullable fields are also reduced. (You can use vanilla JS too if you like.). - [mocks](./jest-mocks.md) for testing - `pickSingle` method was replaced for more streamlined `const [result] = pick()` ### iOS - new: [`saveDocuments`](./picker/save-as-dialog) function - new: [`isKnownType`](./picker/limiting-selectable-files.md#isknowntype) utility - new: support for long-term file access permissions - across app and even device reboots! ([`requestLongTermAccess`](./picker/open-mode.mdx)) - new: [`keepLocalCopy`](./picker/keeping-local-copy.mdx) function that separates picking a file and copying it to a local directory. This makes your app more responsive: previously you'd use the `copyTo` option and before the resulting `Promise` resolved, you needed to wait not only for user to pick the file, but also for the file to be copied to your app's directory. For large files or with slow network, this could be a problem that you, as a dev don't see, but your users do. - improved: the majority of the code is now written in Swift, making code safer and more readable. - improved: less use of the main thread. - improved: using the new `UIDocumentPickerViewController` apis instead of those deprecated in iOS 14 - improved: instead of the old `copyTo` parameter making unnecessary copies, the new `keepLocalCopy` function moves the imported file. ### Android - new: [`saveDocuments`](./picker/save-as-dialog) function - new: support for [open mode](./picker/open-mode.mdx) - new: support for long-term file access permissions - across app and even device reboots! ([`requestLongTermAccess`](./picker/open-mode.mdx)) - new: [`keepLocalCopy`](./picker/keeping-local-copy.mdx) function that separates picking a file and copying it to a local directory. This makes your app more responsive: previously you'd use the `copyTo` option and before the resulting `Promise` resolved, you needed to wait not only for user to pick the file, but also for the file to be copied to your app's directory. For large files or with slow network, this could be a problem that you, as a dev don't see, but your users do. - new: support for [virtual files](./picker/virtual-files.md) - improved: deprecated [AsyncTask](https://developer.android.com/reference/android/os/AsyncTask) usage was replaced with Kotlin Coroutines. - improved: the code is better at operating with I/O, for example buffering is replaced with a potentially much more efficient alternative from `java.nio` - improved: reading file metadata is more defensive and efficient because only the necessary columns are queried from [ContentResolver](). The native Android apis are full of calls that can return null or throw so extra care is taken to handle these cases. ### Windows Windows is not supported at the moment but you can try your luck [here](https://github.com/ClaudiuHBann/document-picker-windows). While there was Windows-related code in the public module, it was not maintained and probably does not work. ### How do I know it works? With so many changes, you might wonder if the new package is stable - especially with Android because... well, we know Android 😜. To prove the new code is solid, I have written an e2e test suite using Appium that covers the majority of the features: - import mode - open mode - viewing files, including long-term permissions The test suite focuses on Android, and was executed on real devices from Samsung, Google and Huawei, with Android versions ranging between 8 and 14. iOS tests were done manually on a real device with iOS 17. As a result, I have greater confidence in the new package than in the old one! ## Say thanks I ([vonovak](https://github.com/vonovak)) have been maintaining the original [`react-native-document-picker`](https://github.com/react-native-documents/document-picker/tree/master) package more or less since 2020. The package has been used by thousands of devs, but I could see that there was a lot to improve. I decided to rewrite the package from scratch and make it better! The new package has a new name: `@react-native-documents/picker`. While I was at it, I also created a new `viewer` package. If you want to say thanks, go to my [GitHub Sponsors profile](https://github.com/sponsors/vonovak). ## Migrating from the old package See the 3-step [migration guide](./migration.md). --- ## Jest module mocks You will need to mock the functionality of the native modules once you require them from your test files - otherwise you'll get [this error](https://github.com/rnmods/react-native-document-picker/issues/702). The packages provide Jest mocks that you can add to the [`setupFiles`](https://jestjs.io/docs/configuration#setupfiles-array) array in the Jest config. By default, the mocks behave as if the calls were successful and return mock document data. ```json title="jest.config" { "setupFiles": [ "./node_modules/@react-native-documents/picker/jest/build/jest/setup.js", "./node_modules/@react-native-documents/viewer/jest/build/jest/setup.js" ] } ``` --- ## Migrating from the old document-picker The new package has a new name (`@react-native-documents/picker`), so you need to update your import statements. ### Migrating your code Good news: You need to make only a few changes: 1. update import statements ```ts import { ... } from 'react-native-document-picker' ``` becomes ```ts import { ... } from '@react-native-documents/picker' ``` Also, if you previously used a default import like this: ```ts import DocumentPicker from 'react-native-document-picker' ``` you should update it to use named imports for the methods you need (such as `pick`, `keepLocalCopy`, etc): ```ts import { pick, keepLocalCopy } from '@react-native-documents/picker' ``` 2. remove `pickSingle` Replace `pickSingle` with `pick`: ```ts const result = await pickSingle(options) ``` becomes: ```ts const [result] = await pick(options) ``` 3. replace `copyTo` with [`keepLocalCopy`](picker/keeping-local-copy.mdx) > This change makes your app more responsive: previously you'd use the `copyTo` option and before the returned `Promise` resolved, you needed to wait not only for the user to pick the file, but also for the file to be copied to your app's directory. For large files or with slow network, this could be a problem that you, as a dev don't see, but your users do. ```ts const localCopy = await pick({ copyTo: 'documentDirectory', }) ``` becomes ```ts const [file] = await pick() const [localCopy] = await keepLocalCopy({ files: [ { uri: file.uri, fileName: file.name ?? 'fallbackName', }, ], destination: 'documentDirectory', }) ``` --- ## Directory picker This module allows you to pick a directory from the file system. The chosen directory can then be used for file I/O operations. When `requestLongTermAccess` is set to `true`, your app will be able to access the directory even after the app is restarted. If you've requested long-term access to a directory or file, the response object will contain [BookmarkingResponse](/docs/doc-picker-api#bookmarkingresponse). Please note there are some [security limitations](https://developer.android.com/training/data-storage/shared/documents-files#document-tree-access-restrictions). ```tsx title="Selecting a directory" import { pickDirectory } from '@react-native-documents/picker' return (