🚀AdvancedAdvanced Forms

File API & FileReader

Read user-selected files in the browser using the File API and FileReader preview images, parse text files, and handle binary data before uploading.

Overview

The File API allows JavaScript running in the browser to read the contents of files selected by the user via `<input type="file">` or drag-and-drop. There is no server round-trip involved the file data is available locally and immediately. A file input's `files` property is a `FileList` of `File` objects. Each `File` extends `Blob` and adds `name`, `size`, `type` (MIME), and `lastModified` properties. You can read the content using three methods: `FileReader` (event-based, older API), `file.text()` / `file.arrayBuffer()` (Promise-based, modern), or `URL.createObjectURL(file)` (creates a temporary browser URL). Use cases include image previews before upload, client-side CSV/JSON parsing, video trimming interfaces, and offline document editors.

Key Points

  • •`input.files` is a `FileList`; individual files are `File` objects (a subtype of `Blob`)
  • •`file.name`, `file.size`, `file.type`, `file.lastModified` are the key File properties
  • •`URL.createObjectURL(file)` fastest way to display/play a file; revoke with `URL.revokeObjectURL(url)` when done
  • •`file.text()` returns a Promise<string> for text files (modern, preferred over FileReader)
  • •`file.arrayBuffer()` returns Promise<ArrayBuffer> for binary files
  • •`FileReader` legacy event-based API; use `.readAsDataURL()`, `.readAsText()`, `.readAsArrayBuffer()`
  • •`input.accept` filters file types in the OS dialog (e.g., `accept="image/*"` or `accept=".pdf,.docx"`)

Examples

Image preview before upload using URL.createObjectURL

<input type="file" id="avatar-input" accept="image/*">
<img id="preview" alt="Preview" style="max-width:300px; display:none">

<script>
document.getElementById('avatar-input').addEventListener('change', (event) => {
  const file = event.target.files[0];
  if (!file) return;

  // Validate type and size
  if (!file.type.startsWith('image/')) {
    alert('Please select an image file.');
    return;
  }
  if (file.size > 5 * 1024 * 1024) {
    alert('Image must be smaller than 5 MB.');
    return;
  }

  const preview = document.getElementById('preview');
  const oldUrl = preview.src;

  // Create a temporary URL and show the preview
  preview.src = URL.createObjectURL(file);
  preview.style.display = 'block';

  // Free memory when the new URL is loaded
  preview.onload = () => URL.revokeObjectURL(oldUrl);
});
</script>

Always revoke object URLs when you no longer need them to free memory.

Reading a text or CSV file with the modern Promise API

<input type="file" id="csv-input" accept=".csv,text/csv">
<pre id="output"></pre>

<script>
document.getElementById('csv-input').addEventListener('change', async (event) => {
  const file = event.target.files[0];
  if (!file) return;

  try {
    // Modern Promise-based read no FileReader needed
    const text = await file.text();
    const rows = text.split('\n').map(row => row.split(','));

    document.getElementById('output').textContent =
      rows.map(r => r.join(' | ')).join('\n');
  } catch (err) {
    console.error('Failed to read file:', err);
  }
});
</script>

file.text() is much cleaner than FileReader use it for any text format (CSV, JSON, XML, markdown).

FileReader for legacy environments or progress events

<input type="file" id="legacy-input">
<progress id="progress" value="0" max="100" style="display:none"></progress>
<div id="result"></div>

<script>
document.getElementById('legacy-input').addEventListener('change', (event) => {
  const file = event.target.files[0];
  if (!file) return;

  const reader = new FileReader();
  const progressBar = document.getElementById('progress');
  progressBar.style.display = 'block';

  reader.onprogress = (e) => {
    if (e.lengthComputable) {
      progressBar.value = (e.loaded / e.total) * 100;
    }
  };

  reader.onload = (e) => {
    document.getElementById('result').textContent = e.target.result;
    progressBar.style.display = 'none';
  };

  reader.onerror = () => console.error('Read failed');

  reader.readAsText(file);
});
</script>

FileReader is useful when you need progress events for large files.

Common Mistakes

  • Not revoking object URLs with URL.revokeObjectURL() each URL holds a reference to the file in memory until revoked or the page unloads
  • Trusting file.type for security validation MIME type comes from the OS and can be spoofed. Validate on the server too
  • Using FileReader for simple text/JSON parsing file.text() and file.arrayBuffer() are simpler and Promise-based

Note

For multiple file selection, add the `multiple` attribute to the input and iterate over `input.files` with a `for...of` loop. Each file is processed independently.

Exercises

Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What does URL.createObjectURL(file) return?