browser-fs-access

A ponyfill that brings the File System Access API to every browser, with a seamless fallback to legacy file input and download methods.

Library
npm
v0.38.0
1,584stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
56/100Fair
Development Activity20
Maintenance44
Community60
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
69/100Good
Architecture75
Code Quality55
Innovation75
Learning Curve70

browser-fs-access is a lightweight JavaScript ponyfill that lets web apps open, save, and browse files and directories through the native File System Access API wherever it is supported, and transparently falls back to <input type="file"> and <a download> in browsers that don’t implement it yet.

Maintained by the Google Chrome team, it powers real-world apps like Excalidraw and SVGcode, exposing a small tree-shakeable API (fileOpen, directoryOpen, fileSave, supported) so teams can adopt native file system access progressively without maintaining two separate code paths.

What You Get

  • Feature-detected fileOpen/directoryOpen/fileSave functions that automatically use the native File System Access API when available
  • Automatic legacy fallback to <input type="file"> and <a download> for unsupported browsers, with matching exception behavior on cancel
  • TypeScript type definitions (index.d.ts) covering every exported function and options object
  • Tree-shakeable ES module build (index.modern.js) plus a CommonJS build for broader bundler compatibility
  • A supported boolean flag apps can read to branch UI/UX based on File System Access API availability
  • Explicit fileOpenModern/fileOpenLegacy (and directory/save equivalents) exports for apps that want to bypass feature detection entirely

Common Use Cases

  • Adding native-feeling “Open” and “Save As” file dialogs to web-based editors and creative tools
  • Building drag-and-drop or picker-based directory import flows for browser-based IDEs
  • Progressively enhancing file upload/download in PWAs without dropping support for older browsers
  • Saving generated files (images, exports, blobs, streamed responses) directly back to a user-chosen location or existing file handle

Under The Hood

Architecture The public API is a thin src/index.js re-export of three dispatcher functions (fileOpen, directoryOpen, fileSave), each of which dynamically imports either the src/fs-access/*.mjs implementation (calling window.showOpenFilePicker/showSaveFilePicker/showDirectoryPicker) or the src/legacy/*.mjs implementation (constructing a hidden <input type="file"> or <a download> element), chosen once at load time via the supported flag computed in src/supported.mjs. This keeps the public signature identical regardless of which implementation runs underneath, with no shared base class or DI container involved — just plain async functions linked to a single shared TypeScript contract in index.d.ts via JSDoc @type annotations. Because every consumer depends on the same three dispatcher files, a defect there affects both the modern and legacy paths simultaneously, which is also what keeps the two implementations’ behavior (multiple-file handling, cancellation errors, webkitRelativePath shape) tightly aligned.

Tech Stack The library has zero runtime dependencies and is written entirely in vanilla ES module JavaScript, targeting the browser’s native File System Access API surface directly rather than wrapping a third-party SDK. It builds with microbundle to emit both a modern ES module and a CommonJS bundle, lints with ESLint (Google config plus eslint-config-prettier) and formats with Prettier, and ships a static demo/ page exercising the API in a real browser rather than a Node-based sandbox. Type definitions are hand-authored in index.d.ts rather than generated, and are wired to the implementation files purely through JSDoc type references.

Code Quality No automated test suite exists in the repository; correctness is instead exercised through the linked demo application and real downstream consumers (Excalidraw, SVGcode). Code is consistently formatted, uses modern JS conventions (const/arrow functions, no var), and every file carries a standard Apache license header plus targeted JSDoc comments explaining non-obvious platform quirks (e.g. cross-origin iframe detection, webkitRelativePath polyfilling). The absence of tests is a real gap for a library gating file I/O behavior across two divergent implementations, though the small, focused file surface limits the blast radius of regressions.

API Design The library’s central design win is collapsing two structurally different browser capabilities into one small, promise-based function surface (fileOpen, directoryOpen, fileSave, supported) that mirrors the shape of the native API closely enough that migrating away from the ponyfill later is close to a no-op. Options objects accept arrays for multi-type filters, sensible defaults (empty extensions, Files description) minimize required boilerplate, and edge cases most consumers would otherwise hand-roll — save-in-place to an existing handle, streaming a Response directly to disk, emulating AbortError on the legacy path — are handled internally rather than pushed onto the caller.

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