Chrome Extension Local File Access — Best Practices

5 min read

Local File Access Patterns in Chrome Extensions

This guide covers various methods for working with local files in Chrome extensions, from simple file input to advanced filesystem APIs.

File System Access API

The File System Access API provides powerful file picker dialogs in extension pages (not content scripts).

// Opening a file with showOpenFilePicker
async function openFile() {
  const [fileHandle] = await window.showOpenFilePicker({
    types: [{
      description: 'Text Files',
      accept: { 'text/plain': ['.txt', '.csv', '.json'] }
    }],
    multiple: false
  });
  const file = await fileHandle.getFile();
  return file;
}

Traditional File Input

Use <input type="file"> in popup or options pages for simpler file selection:

<input type="file" id="fileInput" accept=".csv,.json">
<script>
document.getElementById('fileInput').addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const content = await file.text();
  console.log(content);
});
</script>

Reading Files with FileReader API

// Read as text
const reader = new FileReader();
reader.readAsText(file);
reader.onload = () => console.log(reader.result);

// Read as data URL (for images)
reader.readAsDataURL(file);

// Read as ArrayBuffer (for binary data)
reader.readAsArrayBuffer(file);

Drag and Drop

Enable drag-and-drop file handling in extension pages:

const dropZone = document.getElementById('dropZone');
dropZone.addEventListener('dragover', (e) => e.preventDefault());
dropZone.addEventListener('drop', async (e) => {
  e.preventDefault();
  const file = e.dataTransfer.files[0];
  // Process the dropped file
});

Downloading/Saving Files

Using chrome.downloads API (requires permissions)

chrome.downloads.download({
  url: 'data:text/plain,Hello World',
  filename: 'output.txt'
});

Using Blob URLs

const blob = new Blob(['Hello World'], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'file.txt';
a.click();
URL.revokeObjectURL(url);

Using Data URLs

const dataUrl = 'data:text/plain;base64,SGVsbG8gV29ybGQ=';
chrome.downloads.download({ url: dataUrl, filename: 'decoded.txt' });

File Type Validation

Always validate file types for security:

function validateFile(file, allowedTypes) {
  const ext = file.name.split('.').pop().toLowerCase();
  if (!allowedTypes.includes(ext)) {
    throw new Error(`Invalid file type. Allowed: ${allowedTypes.join(', ')}`);
  }
  return true;
}

Processing Large Files

Use streaming for files larger than available memory:

async function streamReadFile(file) {
  const stream = file.stream();
  const reader = stream.getReader();
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    // Process chunk (value is Uint8Array)
    processChunk(value);
  }
}

Origin Private File System (OPFS)

Store extension-local data using OPFS:

async function writeToOPFS(filename, content) {
  const root = await navigator.storage.getDirectory();
  const fileHandle = await root.getFileHandle(filename, { create: true });
  const writable = await fileHandle.createWritable();
  await writable.write(content);
  await writable.close();
}

Temporary Files with createObjectURL

// Create temporary URL for a Blob
const tempUrl = URL.createObjectURL(blob);
// Use in <img src>, <a href>, etc.
// Remember to revoke when done
URL.revokeObjectURL(tempUrl);

Limitations

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.