// Read file as textasync function readFileAsText(file) { try { const text = await file.text(); console.log("File content:", text); return text; } catch (error) { console.error("Error reading file:", error); }}// Read file as ArrayBufferasync function readFileAsArrayBuffer(file) { try { const buffer = await file.arrayBuffer(); console.log("Buffer size:", buffer.byteLength); return buffer; } catch (error) { console.error("Error reading file:", error); }}// Read file as data URL for previewasync function readFileAsDataURL(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.onerror = () => reject(reader.error); reader.readAsDataURL(file); });}// UsagefileInput.addEventListener("change", async (event) => { const file = event.target.files[0]; if (file.type.startsWith("text/")) { const text = await file.text(); console.log(text); } else if (file.type.startsWith("image/")) { const dataURL = await readFileAsDataURL(file); const img = document.createElement("img"); img.src = dataURL; document.body.appendChild(img); }});// Slice file for chunked uploadfunction uploadFileInChunks(file, chunkSize = 1024 * 1024) { const chunks = Math.ceil(file.size / chunkSize); for (let i = 0; i < chunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, file.size); const chunk = file.slice(start, end); console.log(`Chunk ${i + 1}/${chunks}: ${chunk.size} bytes`); uploadChunk(chunk, i); }}async function uploadChunk(chunk, index) { const formData = new FormData(); formData.append("chunk", chunk); formData.append("index", index); await fetch("/upload-chunk", { "method": "POST", "body": formData });}
Note: File objects are Blob subclasses with additional name and lastModified properties. Files from <input type="file"> are read-only. Use accept attribute to filter file types in picker. Modern methods (text(), arrayBuffer()) are Promise-based and simpler than FileReader.
2. FileReader API for File Content Reading
Method
Description
Result Format
readAsText(blob, encoding)
Reads file as text string. Optional encoding (default UTF-8).
string
readAsDataURL(blob)
Reads file as data URL (base64-encoded). Good for images.
data:image/jpeg;base64,...
readAsArrayBuffer(blob)
Reads file as ArrayBuffer. Good for binary data.
ArrayBuffer
readAsBinaryString(blob)
Reads file as binary string. Deprecated - use readAsArrayBuffer instead.
Note: FileReader is event-based and asynchronous. For modern code, prefer file.text() or file.arrayBuffer() which return Promises. readAsDataURL creates large base64 strings - consider object URLs for better performance. Each FileReader instance can only read one file at a time.
3. Clipboard API for Copy/Paste Operations
Method
Description
Browser Support
navigator.clipboard.writeText(text)
Writes text to clipboard. Returns Promise. Requires user gesture or permission.
Modern Browsers
navigator.clipboard.readText()
Reads text from clipboard. Returns Promise<string>. Requires permission.
Modern Browsers
navigator.clipboard.write(items)
Writes ClipboardItem array to clipboard. Supports images, rich content.
Modern Browsers
navigator.clipboard.read()
Reads ClipboardItem array from clipboard. Returns Promise<ClipboardItem[]>.
Modern Browsers
Legacy Method
Description
Status
document.execCommand("copy")
Copies selected text to clipboard. Deprecated but widely supported.
DEPRECATED
document.execCommand("cut")
Cuts selected text to clipboard. Deprecated but widely supported.
DEPRECATED
document.execCommand("paste")
Pastes from clipboard. Deprecated and security restricted.
DEPRECATED
Example: Modern clipboard API
// Copy text to clipboardasync function copyToClipboard(text) { try { await navigator.clipboard.writeText(text); console.log("Text copied to clipboard"); return true; } catch (error) { console.error("Failed to copy:", error); return false; }}// Read text from clipboardasync function readFromClipboard() { try { const text = await navigator.clipboard.readText(); console.log("Clipboard content:", text); return text; } catch (error) { console.error("Failed to read clipboard:", error); return null; }}// Copy button handlerdocument.querySelector(".copy-btn").addEventListener("click", async () => { const text = document.querySelector(".codeBlock").textContent; const success = await copyToClipboard(text); if (success) { // Show feedback showToast("Copied to clipboard!"); }});// Paste handlerdocument.querySelector(".paste-btn").addEventListener("click", async () => { const text = await readFromClipboard(); if (text) { document.querySelector("textarea").value = text; }});// Copy rich content (HTML, images)async function copyRichContent() { const blob = new Blob( ["<h1>Hello</h1><p>Rich content</p>"], { "type": "text/html" } ); const item = new ClipboardItem({ "text/html": blob }); try { await navigator.clipboard.write([item]); console.log("Rich content copied"); } catch (error) { console.error("Failed to copy rich content:", error); }}// Copy image to clipboardasync function copyImageToClipboard(imageUrl) { try { const response = await fetch(imageUrl); const blob = await response.blob(); const item = new ClipboardItem({ [blob.type]: blob }); await navigator.clipboard.write([item]); console.log("Image copied to clipboard"); } catch (error) { console.error("Failed to copy image:", error); }}// Read clipboard with multiple formatsasync function readClipboardData() { try { const items = await navigator.clipboard.read(); for (const item of items) { console.log("Clipboard item types:", item.types); for (const type of item.types) { const blob = await item.getType(type); if (type.startsWith("text/")) { const text = await blob.text(); console.log(`${type}:`, text); } else if (type.startsWith("image/")) { const url = URL.createObjectURL(blob); console.log(`${type}:`, url); const img = document.createElement("img"); img.src = url; document.body.appendChild(img); } } } } catch (error) { console.error("Failed to read clipboard:", error); }}
Example: Legacy execCommand fallback
// Copy with fallbackasync function copyText(text) { // Try modern API if (navigator.clipboard && navigator.clipboard.writeText) { try { await navigator.clipboard.writeText(text); return true; } catch (error) { console.warn("Clipboard API failed, trying fallback"); } } // Fallback to execCommand const textarea = document.createElement("textarea"); textarea.value = text; textarea.style.position = "fixed"; textarea.style.opacity = "0"; document.body.appendChild(textarea); textarea.select(); let success = false; try { success = document.execCommand("copy"); } catch (error) { console.error("execCommand failed:", error); } document.body.removeChild(textarea); return success;}// Copy from elementfunction copyElementText(element) { const text = element.textContent || element.innerText; return copyText(text);}// Select and copyfunction selectAndCopy(element) { const range = document.createRange(); range.selectNodeContents(element); const selection = window.getSelection(); selection.removeAllRanges(); selection.addRange(range); const success = document.execCommand("copy"); selection.removeAllRanges(); return success;}
Note: Clipboard API requires HTTPS (or localhost). writeText() requires user gesture on some browsers. readText() requires clipboard permission. ClipboardItem supports multiple MIME types. Always provide fallback for older browsers.
Warning: Reading clipboard requires user permission - prompt may appear. Don't spam clipboard writes - annoying UX. execCommand is deprecated but still needed for fallback. Never auto-read clipboard on page load - privacy violation.
4. Drag and Drop API with DataTransfer
Event
Target
When Fired
Cancelable
dragstart
Source element
User starts dragging element
Yes
drag
Source element
While dragging (fires continuously)
Yes
dragend
Source element
Drag operation ends (drop or cancel)
No
dragenter
Drop target
Dragged element enters drop target
Yes
dragover
Drop target
Dragged element over drop target (fires continuously)
Yes
dragleave
Drop target
Dragged element leaves drop target
No
drop
Drop target
Element dropped on target. Must preventDefault() on dragover.
Yes
DataTransfer Property
Type
Description
dropEffect
string
Visual feedback: "none", "copy", "move", "link". Set in dragover.
effectAllowed
string
Allowed operations: "none", "copy", "move", "link", "copyMove", "all", etc. Set in dragstart.
files
FileList
Files being dragged (from file system). Available in drop event.
items
DataTransferItemList
List of drag data items. More powerful than files.
types
string[]
Array of data format types available.
DataTransfer Method
Description
setData(format, data)
Sets drag data. Common formats: "text/plain", "text/html", "text/uri-list".
getData(format)
Gets drag data. Only accessible in drop event.
clearData(format)
Clears drag data. Optional format parameter.
setDragImage(element, x, y)
Sets custom drag preview image. x, y are hotspot offsets.
Example: Basic drag and drop
// Make element draggableconst draggable = document.querySelector(".draggable");draggable.draggable = true;// Drag startdraggable.addEventListener("dragstart", (event) => { console.log("Drag started"); // Set data event.dataTransfer.setData("text/plain", event.target.id); event.dataTransfer.setData("text/html", event.target.outerHTML); // Set effect event.dataTransfer.effectAllowed = "move"; // Visual feedback event.target.style.opacity = "0.5";});// Drag enddraggable.addEventListener("dragend", (event) => { console.log("Drag ended"); event.target.style.opacity = "1";});// Drop targetconst dropZone = document.querySelector(".drop-zone");// Prevent default to allow dropdropZone.addEventListener("dragover", (event) => { event.preventDefault(); event.dataTransfer.dropEffect = "move";});// Visual feedbackdropZone.addEventListener("dragenter", (event) => { event.preventDefault(); dropZone.classList.add("drag-over");});dropZone.addEventListener("dragleave", () => { dropZone.classList.remove("drag-over");});// Handle dropdropZone.addEventListener("drop", (event) => { event.preventDefault(); dropZone.classList.remove("drag-over"); // Get data const id = event.dataTransfer.getData("text/plain"); console.log("Dropped element ID:", id); // Move element const element = document.getElementById(id); dropZone.appendChild(element);});
Example: File drag and drop
const dropZone = document.getElementById("file-drop-zone");// Prevent default browser behavior["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { dropZone.addEventListener(eventName, (e) => { e.preventDefault(); e.stopPropagation(); });});// Visual feedback["dragenter", "dragover"].forEach((eventName) => { dropZone.addEventListener(eventName, () => { dropZone.classList.add("highlight"); });});["dragleave", "drop"].forEach((eventName) => { dropZone.addEventListener(eventName, () => { dropZone.classList.remove("highlight"); });});// Handle dropped filesdropZone.addEventListener("drop", (event) => { const files = event.dataTransfer.files; console.log(`${files.length} file(s) dropped`); // Process files Array.from(files).forEach((file) => { console.log("File:", file.name, file.type, file.size); handleFile(file); }); // Or use DataTransferItemList for more control const items = event.dataTransfer.items; for (let i = 0; i < items.length; i++) { const item = items[i]; if (item.kind === "file") { const file = item.getAsFile(); console.log("File from item:", file.name); } }});// Validate dropped filesfunction validateDrop(event) { const items = event.dataTransfer.items; for (let i = 0; i < items.length; i++) { const item = items[i]; // Check if file if (item.kind !== "file") { return false; } // Check file type if (!item.type.startsWith("image/")) { alert("Only images allowed"); return false; } } return true;}// Preview dropped imagesasync function handleFile(file) { if (!file.type.startsWith("image/")) return; const img = document.createElement("img"); img.file = file; const reader = new FileReader(); reader.onload = (e) => { img.src = e.target.result; img.style.maxWidth = "200px"; dropZone.appendChild(img); }; reader.readAsDataURL(file);}
Note: Must call preventDefault() on dragover event to allow drop. getData() only works in drop event (security). Set draggable="true" attribute on elements to make draggable. Use event.dataTransfer.files for dropped files.
Warning:dragover fires very frequently - throttle expensive operations. Some browsers restrict file access from drag/drop for security. Always validate dropped files before processing. Mobile browsers have limited drag/drop support.
5. File System Access API for Local Files
Method
Description
Browser Support
window.showOpenFilePicker(options)
Shows file picker. Returns Promise<FileSystemFileHandle[]>. Requires user gesture.
Modern Browsers
window.showSaveFilePicker(options)
Shows save dialog. Returns Promise<FileSystemFileHandle>. Requires user gesture.
Modern Browsers
window.showDirectoryPicker(options)
Shows directory picker. Returns Promise<FileSystemDirectoryHandle>. Requires user gesture.
Modern Browsers
FileSystemFileHandle Method
Description
getFile()
Returns Promise<File> with file contents.
createWritable()
Returns Promise<FileSystemWritableFileStream> for writing.
queryPermission(descriptor)
Checks permission status. Returns "granted", "denied", or "prompt".
requestPermission(descriptor)
Requests permission. Returns "granted" or "denied".
Note: File System Access API requires user gesture (click event). Only works in secure contexts (HTTPS). Browser shows permission prompt for each file access. File handles can be persisted in IndexedDB for later use. Very limited browser support (mainly Chrome).
6. Directory Handle and File Handle APIs
FileSystemDirectoryHandle Method
Description
getFileHandle(name, options)
Gets file in directory. Options: create: true to create if missing.
getDirectoryHandle(name, options)
Gets subdirectory. Options: create: true to create if missing.
removeEntry(name, options)
Removes file/directory. Options: recursive: true for directories.
values()
Returns async iterator of entries in directory.
keys()
Returns async iterator of entry names.
entries()
Returns async iterator of [name, handle] pairs.
Example: Directory operations
// Pick directoryasync function pickDirectory() { try { const dirHandle = await window.showDirectoryPicker(); console.log("Directory:", dirHandle.name); // List contents await listDirectory(dirHandle); return dirHandle; } catch (error) { console.error("Error picking directory:", error); }}// List directory contentsasync function listDirectory(dirHandle) { console.log(`Contents of ${dirHandle.name}:`); for await (const entry of dirHandle.values()) { console.log(` ${entry.kind}: ${entry.name}`); if (entry.kind === "file") { const file = await entry.getFile(); console.log(` Size: ${file.size} bytes`); } }}// Read all files in directoryasync function readAllFiles(dirHandle) { const files = []; for await (const entry of dirHandle.values()) { if (entry.kind === "file") { const file = await entry.getFile(); const content = await file.text(); files.push({ name: file.name, content }); } } return files;}// Create file in directoryasync function createFileInDirectory(dirHandle, fileName, content) { try { const fileHandle = await dirHandle.getFileHandle(fileName, { "create": true }); const writable = await fileHandle.createWritable(); await writable.write(content); await writable.close(); console.log(`Created: ${fileName}`); } catch (error) { console.error("Error creating file:", error); }}// Create subdirectoryasync function createSubdirectory(dirHandle, dirName) { try { const subDirHandle = await dirHandle.getDirectoryHandle(dirName, { "create": true }); console.log(`Created directory: ${dirName}`); return subDirHandle; } catch (error) { console.error("Error creating directory:", error); }}// Delete fileasync function deleteFile(dirHandle, fileName) { try { await dirHandle.removeEntry(fileName); console.log(`Deleted: ${fileName}`); } catch (error) { console.error("Error deleting file:", error); }}// Recursively list directory treeasync function listDirectoryTree(dirHandle, indent = "") { for await (const [name, handle] of dirHandle.entries()) { console.log(`${indent}${handle.kind === "directory" ? "š" : "š"} ${name}`); if (handle.kind === "directory") { await listDirectoryTree(handle, indent + " "); } }}// Search for filesasync function findFiles(dirHandle, pattern) { const results = []; for await (const entry of dirHandle.values()) { if (entry.kind === "file" && entry.name.includes(pattern)) { results.push(entry); } else if (entry.kind === "directory") { const subResults = await findFiles(entry, pattern); results.push(...subResults); } } return results;}
Warning: File System Access API has very limited browser support (mainly Chrome/Edge). Always check if ("showOpenFilePicker" in window). Requires user permission for each directory access. Writing files requires explicit user consent. Not available in iframes or insecure contexts.
File and Clipboard API Best Practices
Validate file type and size before processing - check file.type and file.size
Use modern file.text() and file.arrayBuffer() instead of FileReader when possible
Use object URLs (URL.createObjectURL) instead of data URLs for better performance
Always revoke object URLs with URL.revokeObjectURL() when done to free memory
For clipboard, provide fallback to execCommand for older browser support
Request clipboard permission with clear explanation - users are wary of clipboard access
For drag and drop, always preventDefault() on dragover to enable drop