useFilePicker

A React hook that opens the browser's native file selector, reads file contents, and validates selections by type, size, and count.

Library
npm
v2.1.4
306stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance20
Community52
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture72
Code Quality78
Innovation55
Learning Curve85

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 returning openFilePicker, filesContent, plainFiles, loading, errors, and clear
  • useImperativeFilePicker() 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, and PersistentFileAmountLimitValidator
  • An extensible Validator base class with validateBeforeParsing/validateAfterParsing hooks 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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search