The useFilePicker() composable opens the browser’s file dialog from your own code and hands you the picked File objects, without rendering a file input. You call openFilePicker() from a click handler (or any other user interaction) and get the files back as a Promise, through the acceptedPickerFiles reactive Array and through the onChange hook.
The picked files go through the same validation as QFile and QUploader (accept, maxFileSize, maxTotalSize, maxFiles and filter), and the files that do not pass are reported the same way those components emit @rejected.
Use it when you want a button, a menu entry, a keyboard shortcut or a card to pick files, and QFile’s field design or QUploader’s queue would get in the way. To accept dropped files as well, pair it with the useDropZone composable, which shares its validation options.
On the server-side of SSR or SSG modes, the file dialog cannot be opened: openFilePicker() resolves to null and acceptedPickerFiles stays empty until the client takes over.
The composable can also be called outside of setup(): in a boot file, a store or a plain module. It works the same there, and there is nothing to release.
Syntax
import { useFilePicker } from 'quasar'
setup () {
const {
acceptedPickerFiles,
rejectedPickerFiles,
openFilePicker,
resetFilePicker
} = useFilePicker({
// all optional:
multiple: true, // allow picking more than one file (default: false)
accept: 'image/*,.pdf', // same format as the native "accept" attribute (default: any file)
capture: 'environment', // 'user' or 'environment'; asks mobile devices for the camera (default: none)
directory: true, // pick a folder instead of files (default: false)
// validation, same meaning as the QFile/QUploader props:
maxFileSize: 1048576, // bytes (default: no limit)
maxTotalSize: 10485760, // bytes (default: no limit)
maxFiles: 5, // (default: no limit)
filter (files) { // keep only the files you return (default: keep them all)
return files.filter(file => file.name.endsWith('.jpg'))
},
onChange (files) {}, // the accepted files of a selection
onRejected (rejected) {}, // [{ failedPropValidation, file }, ...]
onCancel () {} // the dialog was dismissed
})
// ...
}function useFilePicker(
options?: MaybeRefOrGetter<{
multiple?: boolean
accept?: string
capture?: 'user' | 'environment'
directory?: boolean
maxFileSize?: string | number
maxTotalSize?: string | number
maxFiles?: string | number
filter?: (files: readonly File[]) => readonly File[]
onChange?: (files: File[]) => void
onRejected?: (rejected: QRejectedEntry[]) => void
onCancel?: () => void
}>
): {
acceptedPickerFiles: ShallowRef<File[]>
rejectedPickerFiles: ShallowRef<QRejectedEntry[]>
openFilePicker: (overrides?: UseFilePickerOptions) => Promise<File[] | null>
resetFilePicker: () => void
}
// UseFilePickerOptions is the type of the "options" parameter above;
// QRejectedEntry is the type of the entries of the QFile/QUploader "rejected" event
interface QRejectedEntry {
failedPropValidation:
| 'accept'
| 'max-file-size'
| 'max-total-size'
| 'filter'
| 'max-files'
| 'duplicate'
file: File
}openFilePicker() must be called as a direct consequence of a user interaction (a click or keyup handler, for example). Browsers refuse to show the file dialog otherwise, including from an async callback that already awaited something.
The Promise returned by openFilePicker() resolves with the accepted files (an empty Array when every picked file got rejected) or with null when the user dismisses the dialog. It also resolves with null when openFilePicker() gets called again before the previous dialog reported, or when your component gets destroyed.
acceptedPickerFiles holds the accepted files of the latest selection. A selection where every file gets rejected leaves acceptedPickerFiles unchanged; rejectedPickerFiles always reflects the latest selection. resetFilePicker() empties both.
onChange is called only when at least one file got accepted, onRejected only when at least one file got rejected (both can be called for the same selection), and onCancel when the dialog was dismissed.
Setting directory picks a folder: the Array holds every file inside it (recursively), with each file’s path relative to the picked folder available as file.webkitRelativePath. The multiple option does not matter in this case. Safari’s dialog also lets the user pick individual files here; those come with an empty webkitRelativePath.
The failedPropValidation of a rejected entry is one of accept, max-file-size, max-total-size, max-files or filter, naming the option that the file did not pass (duplicate belongs to the same QRejectedEntry type, but only QFile and QUploader can report it, when appending to a list).
Changing the options
The options can be a plain Object, a Ref or a getter Function, and they are read each time openFilePicker() is called. You can also hand over overrides to openFilePicker() itself, which take precedence for that one call:
import { ref } from 'vue'
import { useFilePicker } from 'quasar'
setup () {
const allowVideos = ref(false)
const { openFilePicker } = useFilePicker(() => ({
multiple: true,
accept: allowVideos.value ? 'image/*,video/*' : 'image/*'
}))
function pickAvatar () {
// only one image for the avatar, whatever the current options say
return openFilePicker({ multiple: false, accept: 'image/*' })
}
// ...
}Example
A button that opens the file dialog for images, lists what was accepted, and reports the rejected files and a dismissed dialog through notifications:
The same picker can serve different needs by handing overrides to openFilePicker(). The second button picks a whole folder and lists the paths relative to it:
To preview a picked image (or hand any picked file to an <img>, a <video> or a download link), pair it with the useObjectUrl composable, which creates the object URL for the File and revokes it when it is no longer needed.