UseFilePicker
Simple react hook to open browser file selector.
Install / Use
/learn @Jaaneek/UseFilePickerREADME
<center>Welcome to use-file-picker 👋</center>
Simple react hook to open browser file selector.
🏠 Homepage
Documentation
Install
npm i use-file-picker
or
yarn add use-file-picker
Usage
Simple txt file content reading
import { useFilePicker } from 'use-file-picker';
import React from 'react';
export default function App() {
const { openFilePicker, filesContent, loading } = useFilePicker({
accept: '.txt',
});
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<button onClick={() => openFilePicker()}>Select files</button>
<br />
{filesContent.map((file, index) => (
<div key={index}>
<h2>{file.name}</h2>
<div key={index}>{file.content}</div>
<br />
</div>
))}
</div>
);
}
Reading and rendering Images
import { useFilePicker } from 'use-file-picker';
import {
FileAmountLimitValidator,
FileTypeValidator,
FileSizeValidator,
ImageDimensionsValidator,
} from 'use-file-picker/validators';
export default function App() {
const { openFilePicker, filesContent, loading, errors } = useFilePicker({
readAs: 'DataURL',
accept: 'image/*',
multiple: true,
validators: [
new FileAmountLimitValidator({ max: 1 }),
new FileTypeValidator(['jpg', 'png']),
new FileSizeValidator({ maxFileSize: 50 * 1024 * 1024 /* 50 MB */ }),
new ImageDimensionsValidator({
maxHeight: 900, // in pixels
maxWidth: 1600,
minHeight: 600,
minWidth: 768,
}),
],
});
if (loading) {
return <div>Loading...</div>;
}
if (errors.length) {
return <div>Error...</div>;
}
return (
<div>
<button onClick={() => openFilePicker()}>Select files </button>
<br />
{filesContent.map((file, index) => (
<div key={index}>
<h2>{file.name}</h2>
<img alt={file.name} src={file.content}></img>
<br />
</div>
))}
</div>
);
}
On change callbacks
import { useFilePicker } from 'use-file-picker';
export default function App() {
const { openFilePicker, filesContent, loading, errors } = useFilePicker({
readAs: 'DataURL',
accept: 'image/*',
multiple: true,
onFilesSelected: ({ plainFiles, filesContent, errors }) => {
// this callback is always called, even if there are errors
console.log('onFilesSelected', plainFiles, filesContent, errors);
},
onFilesRejected: ({ errors }) => {
// this callback is called when there were validation errors
console.log('onFilesRejected', errors);
},
onFilesSuccessfullySelected: ({ plainFiles, filesContent }) => {
// this callback is called when there were no validation errors
console.log('onFilesSuccessfullySelected', plainFiles, filesContent);
},
});
if (loading) {
return <div>Loading...</div>;
}
if (errors.length) {
return <div>Error...</div>;
}
return (
<div>
<button onClick={() => openFilePicker()}>Select files </button>
<br />
{filesContent.map((file, index) => (
<div key={index}>
<h2>{file.name}</h2>
<img alt={file.name} src={file.content}></img>
<br />
</div>
))}
</div>
);
}
Advanced usage
import { useFilePicker } from 'use-file-picker';
import React from 'react';
export default function App() {
const { openFilePicker, filesContent, loading, errors, plainFiles, clear } = useFilePicker({
multiple: true,
readAs: 'DataURL', // availible formats: "Text" | "BinaryString" | "ArrayBuffer" | "DataURL"
// accept: '.ics,.pdf',
accept: ['.json', '.pdf'],
validators: [new FileAmountLimitValidator({ min: 2, max: 3 })],
// readFilesContent: false, // ignores file content
});
if (errors.length) {
return (
<div>
<button onClick={() => openFilePicker()}>Something went wrong, retry! </button>
{errors.map(err => (
<div>
{err.name}: {err.reason}
/* e.g. "name":"FileAmountLimitError", "reason":"MAX_AMOUNT_OF_FILES_EXCEEDED" */
</div>
))}
</div>
);
}
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<button onClick={() => openFilePicker()}>Select file </button>
<button onClick={() => clear()}>Clear</button>
<br />
Number of selected files:
{plainFiles.length}
<br />
{/* If readAs is set to DataURL, You can display an image */}
{!!filesContent.length && <img src={filesContent[0].content} />}
<br />
{plainFiles.map(file => (
<div key={file.name}>{file.name}</div>
))}
</div>
);
}
Callbacks
You can hook your logic into callbacks that will be fired at specific events during the lifetime of the hook. useFilePicker accepts these callbacks:
- onFilesSelected
- onFilesRejected
- onFilesSuccessfullySelected
- onClear
These are described in more detail in the Props section.
import { useFilePicker } from 'use-file-picker';
export default function App() {
const { openFilePicker, filesContent, loading, errors, plainFiles, clear } = useFilePicker({
multiple: true,
readAs: 'DataURL',
accept: ['.json', '.pdf'],
onFilesSelected: ({ plainFiles, filesContent, errors }) => {
// this callback is always called, even if there are errors
console.log('onFilesSelected', plainFiles, filesContent, errors);
},
onFilesRejected: ({ errors }) => {
// this callback is called when there were validation errors
console.log('onFilesRejected', errors);
},
onFilesSuccessfullySelected: ({ plainFiles, filesContent }) => {
// this callback is called when there were no validation errors
console.log('onFilesSuccessfullySelected', plainFiles, filesContent);
},
onClear: () => {
// this callback is called when the selection is cleared
console.log('onClear');
},
});
}
useImperativePicker hook also accepts the callbacks listed above. Additionally, it accepts the onFileRemoved callback, which is called when a file is removed from the list of selected files.
import { useImperativeFilePicker } from 'use-file-picker';
export default function App() {
const { openFilePicker, filesContent, loading, errors, plainFiles, clear } = useImperativeFilePicker({
onFileRemoved: (removedFile, removedIndex) => {
// this callback is called when a file is removed from the list of selected files
console.log('onFileRemoved', removedFile, removedIndex);
},
});
}
Keeping the previously selected files and removing them from selection on demand
If you want to keep the previously selected files and remove them from the selection, you can use a separate hook called useImperativeFilePicker that is also exported in this package. For files removal, you can use removeFileByIndex or removeFileByReference functions.
import React from 'react';
import { useImperativeFilePicker } from 'use-file-picker';
const Imperative = () => {
const { openFilePicker, filesContent, loading, errors, plainFiles, clear, removeFileByIndex, removeFileByReference } =
useImperativeFilePicker({
multiple: true,
readAs: 'Text',
readFilesContent: true,
});
if (errors.length) {
return (
<div>
<button onClick={() => openFilePicker()}>Something went wrong, retry! </button>
<div style={{ display: 'flex', flexDirection: 'column' }}>
{console.log(errors)}
{errors.map(err => (
<div>
{err.name}: {err.reason}
/* e.g. "name":"FileAmountLimitError", "reason":"MAX_AMOUNT_OF_FILES_EXCEEDED" */
</div>
))}
</div>
</div>
);
}
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<button onClick={async () => openFilePicker()}>Select file</button>
<button onClick={() => clear()}>Clear</button>
<br />
Amount of selected files:
{plainFiles.length}
<br />
Amount of filesContent:
{filesContent.length}
<br />
{plainFiles.map((file, i) => (
<div>
<div style={{ display: 'flex', alignItems: 'center' }} key={file.name}>
<div>{file.name}</div>
<button style={{ marginLeft: 24 }} onClick={() => removeFileByReference(file)}>
Remove by reference
</button>
<button style={{ marginLeft: 24 }} onClick={() => removeFileByIndex(i)}>
Remove by index
</button>
</div>
<div>{filesContent[i]?.content}</div>
</div>
))}
</div>
);
};
``
