useFilePicker
A React hook that opens the browser's native file selector, reads file contents, and validates selections by type, size, and count.
Repository Health
Technical Analysis
use-file-picker is a lightweight React hook that wraps the browser’s native file input behind a simple useFilePicker() call, so components can open a file dialog, read the resulting files as text, a data URL, binary string, or array buffer, and validate them without manually wiring up a hidden <input type="file"> element.
Validation is handled by a small extensible Validator class with validateBeforeParsing and validateAfterParsing lifecycle hooks, and the package ships built-in validators for file count limits, MIME/extension type checks, file size limits, and image dimension constraints. A companion useImperativeFilePicker hook adds imperative control for removing individual files from an already-selected set by index or reference, which the base hook does not support.
What You Get
useFilePicker()hook returningopenFilePicker,filesContent,plainFiles,loading,errors, andclearuseImperativeFilePicker()variant that additionally supports removing individual files by index or reference after selection- Configurable content reading via
readAs: Text, DataURL, BinaryString, or ArrayBuffer, with selectable text encoding - Built-in validators:
FileAmountLimitValidator,FileTypeValidator,FileSizeValidator,ImageDimensionsValidator, andPersistentFileAmountLimitValidator - An extensible
Validatorbase class withvalidateBeforeParsing/validateAfterParsinghooks for writing custom validation logic - Lifecycle callbacks —
onFilesSelected,onFilesSuccessfullySelected,onFilesRejected,onClear,onFileRemoved— for hooking application logic into the selection flow
Common Use Cases
- Reading small text or JSON config files uploaded by a user directly in the browser, without a server round-trip
- Building an image upload preview that enforces file type, size, and pixel-dimension constraints before submission
- Multi-file upload widgets that need to cap the number of files a user can attach and show validation errors inline
- Forms that need to accumulate selections across multiple picker invocations and let the user remove individual files before submitting
- Prototyping file-handling UI quickly without hand-rolling a hidden
<input type="file">and FileReader plumbing
Under The Hood
Architecture
The library is organized as a small pnpm/Turborepo monorepo with the published package isolated under packages/use-file-picker/src. The core useFilePicker hook (src/useFilePicker.ts) composes three concerns behind React state: a DOM helper (helpers/openFileDialog.ts) that creates a hidden <input type="file">, dispatches a synthetic click, and cleans itself up on change or cancel; a FileReader-based parseFile routine that resolves each file’s content according to the configured readAs strategy; and a useValidators hook that wires the lifecycle callbacks (onFilesSelected, onFilesRejected, etc.) declared on any passed-in Validator instances. useImperativeFilePicker (src/useImperativeFilePicker.ts) layers file removal (by index or reference) on top of the same primitives. State flow is single-directional: selection triggers a before-parsing validation pass across all files, then a per-file after-parsing pass, with plainFiles/filesContent/errors state only committed once both passes resolve — a change to the validator contract would ripple through both hooks and every built-in validator.
Tech Stack
Written in TypeScript (strict mode, noUncheckedIndexedAccess, noImplicitOverride) targeting ES2015, built with pkgroll into dual CJS/ESM output with generated .d.ts types, and published with peerDependencies on react/@types/react (>=16) so it never bundles its own React copy. The only runtime dependency is file-selector (also used by react-dropzone) for normalizing FileWithPath objects from DOM file-selection events. The repo uses pnpm workspaces plus Turborepo to coordinate the library package and a separate packages/example demo app, with ESLint (typescript-eslint + eslint-plugin-react) and Prettier for linting/formatting.
Code Quality
Tests live under packages/use-file-picker/test and run on Vitest with @testing-library/react, @testing-library/user-event, and happy-dom, covering the base hook, the imperative hook, and each built-in validator (amount, size, type) with dedicated test files. Error handling is explicit and typed — validators reject with structured UseFilePickerError objects rather than throwing, and FileReader errors are surfaced through the same error channel. Naming is consistent and descriptive (validateBeforeParsing/validateAfterParsing, onFilesSuccessfullySelected), and the public API is fully typed via generics that thread a custom error type and config type through the hook’s return shape.
What Makes It Unique
Rather than exposing a single opinionated validation API, the package separates “before parsing” (operates on raw File objects, once per selection) from “after parsing” (operates on parsed content, once per file) as two distinct validator lifecycle stages, letting a single Validator subclass cheaply express constraints that depend on either the full batch or an individual file’s read result. The imperative variant’s reference-based file removal (removeFileByReference) is a comparatively uncommon capability among lightweight file-picker hooks, most of which only support clearing the entire selection at once.
Used by 2 apps in this directory
fountain-ink
Blogging
A self-hostable, decentralized blogging platform built on Lens Protocol — own your content, audience, and distribution forever.
Teable
Databases · No Code Platforms
A no-code PostgreSQL database with spreadsheet UX, real-time collaboration, and native AI agents — built for teams that outgrow Airtable.