The File System Access API lets browser-side JavaScript read and write files on the user’s local filesystem with their explicit permission. In WordPress admin tools or media helpers this enables drag-to-edit workflows — for example, editing a CSS file directly from the browser without an FTP client.
Problem: A WordPress admin tool needs to read or write files directly on the user's local machine — for example, importing a large CSV or exporting a configuration file — without requiring a server upload or download.
Solution: Use the File System Access API — call window.showOpenFilePicker() to let the user select a file, read it with a FileSystemFileHandle, and write changes back with createWritable(). All file I/O happens locally in the browser without any server round-trip.
The examples below open a file picker for a single file, read and display its content in a textarea, then write the modified content back to the same file — all without a server round-trip.
// file-editor.js — enqueued on a custom WP admin page
let fileHandle = null;
// 1. Open a file picker (requires a user gesture — attach to a button click)
document.getElementById( 'btn-open' ).addEventListener( 'click', async () => {
try {
[ fileHandle ] = await window.showOpenFilePicker( {
types: [
{
description: 'CSS / JS files',
accept: { 'text/css': ['.css'], 'text/javascript': ['.js'] },
},
],
excludeAcceptAllOption: false,
multiple: false,
} );
const file = await fileHandle.getFile();
const content = await file.text();
document.getElementById( 'editor-textarea' ).value = content;
document.getElementById( 'file-name' ).textContent = file.name;
document.getElementById( 'btn-save' ).disabled = false;
} catch ( err ) {
if ( err.name !== 'AbortError' ) console.error( err );
}
} );
// 2. Save the edited content back to the original file
document.getElementById( 'btn-save' ).addEventListener( 'click', async () => {
if ( ! fileHandle ) return;
// Request write permission (browser will prompt if not already granted)
const perm = await fileHandle.requestPermission( { mode: 'readwrite' } );
if ( perm !== 'granted' ) return;
const writable = await fileHandle.createWritable();
await writable.write( document.getElementById( 'editor-textarea' ).value );
await writable.close();
showNotice( 'File saved successfully.' );
} );
Handle directory access for batch operations — useful for reading an entire theme folder:
// Open an entire directory and list all CSS files
document.getElementById( 'btn-open-dir' ).addEventListener( 'click', async () => {
const dirHandle = await window.showDirectoryPicker();
const cssFiles = [];
for await ( const [name, handle] of dirHandle ) {
if ( handle.kind === 'file' && name.endsWith( '.css' ) ) {
cssFiles.push( { name, handle } );
}
}
// Render a file list
const list = document.getElementById( 'file-list' );
list.innerHTML = '';
for ( const { name, handle } of cssFiles ) {
const li = document.createElement( 'li' );
li.textContent = name;
li.addEventListener( 'click', async () => {
const file = await handle.getFile();
const content = await file.text();
document.getElementById( 'editor-textarea' ).value = content;
fileHandle = handle;
} );
list.appendChild( li );
}
} );
NOTE: The File System Access API is supported in Chrome and Edge but not in Firefox or Safari. Always check typeof window.showOpenFilePicker === 'function' before using it and provide a server-side fallback upload form for unsupported browsers.