File System Access API: JavaScript File Editing
The File System Access API enables web applications to read, modify, and save files directly on a user’s local device, bridging the gap between web and native desktop applications. This article breaks down the purpose of the API, explains its core mechanisms, and demonstrates how JavaScript requests file handles to open, edit, and persist changes to local files.
What is the File System Access API?
The File System Access API is a modern browser API that gives web
applications direct access to the user’s local file system upon
receiving user permission. Historically, web apps relied on standard
file inputs (<input type="file">) to read data and
simulated downloads via anchor tags to save data. The File System Access
API replaces this clunky workflow by granting read and write access to
specific files and directories, allowing seamless in-place editing.
The API relies on two primary interfaces: -
FileSystemFileHandle: Represents a
reference to a specific file on disk. -
FileSystemDirectoryHandle: Represents a
reference to a directory on disk.
Requesting a File Handle
To interact with a file, you must first obtain a
FileSystemFileHandle. Because accessing the file system
involves user privacy, the request must be triggered by a direct user
action, such as a button click, and executed within a secure context
(HTTPS).
You request a file handle using
window.showOpenFilePicker():
async function getFileHandle() {
const options = {
types: [
{
description: 'Text Files',
accept: {
'text/plain': ['.txt', '.md'],
},
},
],
excludeAcceptAllOption: false,
multiple: false,
};
// Open the native file picker
const [fileHandle] = await window.showOpenFilePicker(options);
return fileHandle;
}Reading File Contents
Once you have the FileSystemFileHandle, you can retrieve
the standard File object using the getFile()
method and read its contents with standard web APIs:
async function readFile(fileHandle) {
const file = await fileHandle.getFile();
const contents = await file.text();
return contents;
}Modifying and Writing to the File
To save changes directly back to the original file, you must request
a writable stream from the file handle via
createWritable(). This triggers a permission prompt if
write permissions have not yet been granted.
async function writeFile(fileHandle, contents) {
// Create a FileSystemWritableFileStream to write to
const writable = await fileHandle.createWritable();
// Write the updated data
await writable.write(contents);
// Close the file and persist changes to disk
await writable.close();
}Creating or Saving a New File
If you need to save content to a new file rather than editing an
existing one, use window.showSaveFilePicker() to prompt the
user for a destination and file name:
async function saveNewFile(contents) {
const options = {
suggestedName: 'untitled.txt',
types: [
{
description: 'Text Files',
accept: { 'text/plain': ['.txt'] },
},
],
};
const fileHandle = await window.showSaveFilePicker(options);
await writeFile(fileHandle, contents);
}Complete Workflow Example
Combining these steps allows for a full read-edit-write cycle:
document.getElementById('editButton').addEventListener('click', async () => {
try {
// 1. Prompt user to select a file
const [fileHandle] = await window.showOpenFilePicker();
// 2. Read the file
const file = await fileHandle.getFile();
let text = await file.text();
// 3. Modify the content
text += '\nUpdated by JavaScript via File System Access API.';
// 4. Save the modified content back to the original file
const writable = await fileHandle.createWritable();
await writable.write(text);
await writable.close();
console.log('File successfully updated on disk.');
} catch (error) {
if (error.name !== 'AbortError') {
console.error('File operation failed:', error);
}
}
});Security and Permissions
Browsers enforce strict security boundaries when interacting with the File System Access API: - Explicit User Intent: Operations must originate from an explicit user interaction (e.g., click events). - Origin-Scoped Permissions: Read and write permissions are requested per-file or per-directory and are scoped to the site origin. - Restricted Directories: Access to sensitive operating system folders (such as system files or browser data) is automatically blocked by the browser.