A quick tour of the Web File API

Document Management System (DMS) being setup by IT consultant
The File API enables web applications to access files and their contents when the user makes them available—typically via an control or drag and drop. Selected files are exposed as a FileList, which contains File objects that provide metadata like name, size, type, and last modified date. You can read a file’s contents using FileReader (asynchronously) or FileReaderSync in web workers, and you can also work with binary data through Blob objects.

Modern web apps often need to work with local files—previewing an image before upload, importing a CSV, or reading a text document to populate an editor. The File API is the foundational Web API that makes this possible by letting a page read files the user explicitly provides.

What the File API is for

The File API enables web applications to access files and their contents when the user makes them available, typically through:

When files are provided this way, the browser exposes them to your code as a FileList, which contains one or more File objects.

The core building blocks

There are also handy URL helpers:

How it relates to other file APIs

The File API is the most basic of the web’s file-related APIs: it focuses on reading and processing data the user provides via input or drag-and-drop, including handling binary data via blobs.

				
					<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File API Demo</title>
    <link data-wphbdelayedstyle="style.css" rel="stylesheet" />
    <script type="wphb-delay-type" src="file_API.js" defer></script>
</head>
    
<body>
    <div class="container">
        <header>
            <h1>File API Overview</h1>
            <p>Select a file or drag-and-drop to inspect metadata and read content.</p>
        </header>
    
        <!-- Method 1: Standard Input -->
        <div class="control-group">
            <label for="file-input" class="btn primary">Choose File(s)</label>
            <input type="file" id="file-input" multiple hidden>
            <span id="file-count">No files chosen</span>
        </div>
    
        <!-- Method 2: Drag and Drop Zone -->
        <div id="drop-zone" class="drop-zone">
            <p>📂 Drag & Drop files here</p>
        </div>
    
        <!-- Output Log -->
        <section class="output-area">
            <h3>File Details & Content:</h3>
            <pre id="output">Waiting for interaction...</pre>
            <div id="preview-container"></div>
        </section>
    </div>
<script type="text/javascript" id="wphb-delayed-styles-js">
			(function () {
				const events = ["keydown", "mousemove", "wheel", "touchmove", "touchstart", "touchend"];
				function wphb_load_delayed_stylesheets() {
					document.querySelectorAll("link[data-wphbdelayedstyle]").forEach(function (element) {
						element.setAttribute("href", element.getAttribute("data-wphbdelayedstyle"));
					}),
						 events.forEach(function (event) {
						  window.removeEventListener(event, wphb_load_delayed_stylesheets, { passive: true });
						});
				}
			   events.forEach(function (event) {
				window.addEventListener(event, wphb_load_delayed_stylesheets, { passive: true });
			  });
			})();
		</script></body>

</html>
				
			
				
					:root {
    --bg-color: #1e1e1e;
    --text-color: #e0e0e0;
    --card-bg: #2d2d2d;
    --primary: #4caf50;
    --accent: #2196f3;
    --border: #444;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: var(--bg-color);
    color: var(--text-color);
    display: flex;
    justify-content: center;
    padding: 2rem;
    line-height: 1.6;
}

.container {
    max-width: 700px;
    width: 100%;
}

/* Hide standard input, style label as button */
.btn {
    display: inline-block;
    padding: 10px 20px;
    background-color: var(--primary);
    color: white;
    border-radius: 4px;
    cursor: pointer;
    font-weight: bold;
    transition: opacity 0.2s;
}

.btn:hover {
    opacity: 0.9;
}

/* Drag and Drop Zone */
.drop-zone {
    margin: 20px 0;
    border: 2px dashed var(--border);
    border-radius: 8px;
    padding: 40px;
    text-align: center;
    background-color: var(--card-bg);
    transition: border-color 0.3s, background-color 0.3s;
}

/* Class added via JS when dragging over */
.drop-zone.hover {
    border-color: var(--accent);
    background-color: #2196f320;
    /* Transparent blue */
}

/* Output Area */
.output-area {
    margin-top: 20px;
    padding: 15px;
    background-color: #000;
    border-radius: 4px;
    border: 1px solid var(--border);
}

#output {
    white-space: pre-wrap;
    font-family: 'Consolas', monospace;
    color: #a5d6a7;
}

img.preview-thumb {
    max-width: 150px;
    margin-top: 10px;
    border: 1px solid #fff;
}
				
			
				
					/**
 * Spec Steppin' Series: File API Overview
 * Source: https://developer.mozilla.org/en-US/docs/Web/API/File_API
 */

const fileInput = document.querySelector('#file-input');
const fileCountSpan = document.querySelector('#file-count');
const dropZone = document.querySelector('#drop-zone');
const output = document.querySelector('#output');
const previewContainer = document.querySelector('#preview-container');

// Helper: Format bytes to human-readable string
const formatFileSize = (bytes) => {
	if (bytes === 0) return '0 Bytes';
	const k = 1024;
	const sizes = ['Bytes', 'KB', 'MB', 'GB'];
	const i = Math.floor(Math.log(bytes) / Math.log(k));
	return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};

// Core Function: Process the FileList object
const handleFiles = (files) => {
	output.textContent = ''; // Clear previous log
	previewContainer.replaceChildren(); // Clear previews

	fileCountSpan.textContent = `${files.length} file(s) selected`;

	// The File API gives us a FileList, which is array-like but not an array.
	// We can convert it or loop standardly.
	Array.from(files).forEach((file) => {
		logMetadata(file);
		readFileContent(file);
	});
};

// 1. Inspect Metadata (Synchronous)
const logMetadata = (file) => {
	const logEntry = `
--- File Metadata ---
Name: ${file.name}
Type: ${file.type || 'Unknown'}
Size: ${formatFileSize(file.size)}
Last Modified: ${new Date(file.lastModified).toLocaleString()}
---------------------
`;
	output.textContent += logEntry;
};

// 2. Read Content (Asynchronous via FileReader)
const readFileContent = (file) => {
	const reader = new FileReader();

	// Setup Event Listeners BEFORE reading
	reader.onload = (event) => {
		// Success handler
		const result = event.target.result;

		// Logic to display content based on type
		if (file.type.startsWith('image/')) {
			const img = document.createElement('img');
			img.src = result; // The result is a Data URL (base64)
			img.classList.add('preview-thumb');
			previewContainer.appendChild(img);
			output.textContent += `\n[Image Preview Generated]\n`;
		} else if (
			file.type.startsWith('text/') ||
			file.type === 'application/json'
		) {
			// Truncate text for demo purposes if it's huge
			const previewText =
				result.length > 200 ? result.substring(0, 200) + '...' : result;
			output.textContent += `\nContent Preview:\n${previewText}\n`;
		}
	};

	reader.onerror = (error) => {
		console.error('Error reading file:', error);
		output.textContent += `\nError reading file: ${error.message}\n`;
	};

	// Trigger the read operation
	if (file.type.startsWith('image/')) {
		reader.readAsDataURL(file); // Great for previews
	} else {
		reader.readAsText(file); // Great for CSV, JSON, TXT
	}
};

// --- Event Listeners ---

// A. Standard Input Change
fileInput.addEventListener('change', (e) => {
	handleFiles(e.target.files);
});

// B. Drag and Drop "Gotchas"
// You MUST preventDefault on 'dragover' and 'drop' or the browser
// will open the file in the tab instead of letting JS handle it.

dropZone.addEventListener('dragover', (e) => {
	e.preventDefault();
	dropZone.classList.add('hover'); // Visual cue
});

dropZone.addEventListener('dragleave', () => {
	dropZone.classList.remove('hover');
});

dropZone.addEventListener('drop', (e) => {
	e.preventDefault();
	dropZone.classList.remove('hover');

	// Access the files via the dataTransfer object
	const files = e.dataTransfer.files;
	if (files.length > 0) {
		handleFiles(files);
	}
});

				
			

Takeaway

 If your app needs to import or preview user-selected files in the browser, the File API is where you start: FileListFile/Blob → read contents asynchronously (or synchronously in workers). It’s simple, widely useful, and the base layer for many “bring your own file” experiences on the web.

Share the Post:

Related Posts

small_c_popup.png

Need help?

Let's have a chat...


Login

Jump Back In!

Here at Webolution Designs, we love to learn. This includes sharing things we have learned with you. 

Register

Begin Your Learning Journey Today!

Come back inside to continue your learning journey.