{"id":15972,"library":"browser-fs-access","title":"Browser FS Access API Ponyfill","description":"browser-fs-access is a JavaScript library that provides a simplified, progressive enhancement approach to using the File System Access API in web browsers. It acts as a ponyfill, meaning it offers a consistent API surface while transparently falling back to older, less capable methods like `<input type=\"file\">` and `<a download>` on browsers that do not fully support the File System Access API. This ensures broad compatibility while leveraging modern capabilities where available. The library is currently at version 0.38.0 and maintains an active release cadence, frequently publishing updates and fixes, often on a monthly basis. Key differentiators include its robust fallback mechanism, its origin from GoogleChromeLabs, and its focus on developer ergonomics by abstracting away the complexities of feature detection and legacy API interactions. It ships with TypeScript types for improved developer experience.","status":"active","version":"0.38.0","language":"javascript","source_language":"en","source_url":"https://github.com/GoogleChromeLabs/browser-fs-access","tags":["javascript","file system access","file system access api","file system","ponyfill","typescript"],"install":[{"cmd":"npm install browser-fs-access","lang":"bash","label":"npm"},{"cmd":"yarn add browser-fs-access","lang":"bash","label":"yarn"},{"cmd":"pnpm add browser-fs-access","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The library is ESM-first and primarily consumed via `import` statements. While bundlers can often handle CommonJS, `require()` is not the idiomatic way to use this library in modern browser environments.","wrong":"const { fileOpen } = require('browser-fs-access');","symbol":"fileOpen","correct":"import { fileOpen } from 'browser-fs-access';"},{"note":"Named imports are the standard for this library. Direct CommonJS `require` might lead to issues with bundlers expecting ESM.","wrong":"const directoryOpen = require('browser-fs-access').directoryOpen;","symbol":"directoryOpen","correct":"import { directoryOpen } from 'browser-fs-access';"},{"note":"The library exports multiple named functions. A default import will not provide `fileSave`.","wrong":"import fileSave from 'browser-fs-access'; // Incorrect default import","symbol":"fileSave","correct":"import { fileSave } from 'browser-fs-access';"},{"note":"`supported` is a named export. While `import * as` works, direct named import is more concise for feature detection.","wrong":"import * as fsAccess from 'browser-fs-access'; console.log(fsAccess.supported);","symbol":"supported","correct":"import { supported } from 'browser-fs-access';"},{"note":"TypeScript types are shipped with the package for all exported functions and relevant interfaces.","symbol":"FileSystemAccessTypes","correct":"import type { FileSystemAccessTypes } from 'browser-fs-access';"}],"quickstart":{"code":"import { fileOpen, directoryOpen, fileSave, supported } from 'browser-fs-access';\n\nasync function performFileOperations() {\n  if (supported) {\n    console.log('Using the File System Access API.');\n  } else {\n    console.log('Using the fallback implementation (e.g., <input type=\"file\"> or <a download>).');\n  }\n\n  try {\n    // Open a single image file with specific options\n    const imageBlob = await fileOpen({\n      mimeTypes: ['image/*'],\n      extensions: ['.png', '.jpg', '.jpeg'],\n      description: 'Select an image file',\n      multiple: false,\n      startIn: 'pictures'\n    });\n    console.log(`Opened image: ${imageBlob.name} (type: ${imageBlob.type}, size: ${imageBlob.size} bytes)`);\n\n    // Open multiple text files from a directory, recursively\n    const filesInDir = await directoryOpen({\n      recursive: true,\n      mode: 'read',\n      mimeTypes: ['text/*', 'application/json'],\n      extensions: ['.txt', '.md', '.json']\n    });\n    console.log(`Opened ${filesInDir.length} files in directory. First file: ${filesInDir[0]?.name || 'N/A'}`);\n\n    // Save a new text file created from a Blob\n    const textContent = 'This is a test file saved using browser-fs-access.\\nHello, world!';\n    const textBlob = new Blob([textContent], { type: 'text/plain' });\n    await fileSave(textBlob, {\n      fileName: 'my-document.txt',\n      extensions: ['.txt'],\n      description: 'My Text Document',\n      startIn: 'documents'\n    });\n    console.log('Successfully saved my-document.txt');\n\n  } catch (error) {\n    if (error.name === 'AbortError') {\n      console.log('User cancelled the file picker.');\n    } else {\n      console.error('File operation failed:', error);\n    }\n  }\n}\n\nperformFileOperations();","lang":"typescript","description":"This quickstart demonstrates opening single and multiple files, recursively opening a directory, and saving a file, along with feature detection and error handling using the `browser-fs-access` library."},"warnings":[{"fix":"Update your code to expect `[directoryHandle]` for empty directories when the File System Access API is active, and handle cases where `files.length` might be 1 but represent an empty directory, or check the `kind` property of the handle.","message":"The `directoryOpen()` function's return value for empty directories changed. When the File System Access API is supported and a directory is empty, the function now returns `[directoryHandle]` instead of an empty array `[]`. This is to provide access to the directory handle itself.","severity":"breaking","affected_versions":">=0.32.1"},{"fix":"Design your application's UI and workflow to gracefully handle the different user interactions and capabilities offered by the native File System Access API versus the fallback `<input type=\"file\">` and `<a download>` methods. Use the `supported` export for feature detection.","message":"`browser-fs-access` is a ponyfill, not a polyfill. This means its behavior, user experience (UI for file pickers), and capabilities will differ significantly between browsers fully supporting the File System Access API and those relying on legacy fallbacks. Always test your application across all target browsers to understand these UX variations.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Ensure you are using `browser-fs-access` version 0.35.0 or newer when working with iframes to benefit from the detection and functionality fixes. Thoroughly test file operations in your specific iframe contexts.","message":"Prior to versions 0.33.0 and 0.35.0, there were known issues with proper detection and use of the File System Access API within same-origin and cross-origin iframes, sometimes leading to erroneous fallback usage. While fixed, complex embedding scenarios might still require careful testing.","severity":"gotcha","affected_versions":"<0.35.0"},{"fix":"Inform users about the expected behavior for saving, especially regarding overwriting existing files, and differentiate between browsers with and without full File System Access API support.","message":"When using `fileSave` to overwrite an existing file, the File System Access API will prompt the user for permission. In legacy fallback mode, this functionality is not available, and typically triggers a new download instead of overwriting, leading to a different user experience.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Configure Jest's `transformIgnorePatterns` to include `browser-fs-access` for transformation, e.g., `\"transformIgnorePatterns\": [\"node_modules/(?!browser-fs-access)\"]`. For other bundlers, ensure your configuration correctly handles ESM in `node_modules`.","cause":"The library is distributed as an ESM module, and older versions of Jest or some bundler configurations might not correctly transpile `export` syntax in `node_modules`.","error":"SyntaxError: Unexpected token 'export' (when using with Jest or older bundlers)"}],"ecosystem":"npm"}