HTML APIs — Geolocation, Drag & Drop, File API
In this tutorial, you'll learn about HTML APIs. We cover key concepts, practical examples, and best practices.
Modern browsers expose powerful APIs directly in HTML and JavaScript — geolocation for maps, drag-and-drop for interactive interfaces, and the File API for client-side file processing.
In this tutorial, you'll learn three built-in HTML APIs — Geolocation for getting user position, Drag and Drop for building interactive interfaces, and the File API for reading files in the browser without a server. These APIs let you build rich applications with zero external dependencies. By the end, you'll combine all three in a practical file upload dashboard.
Real-world use: Durga Antivirus Pro uses the File API to scan locally selected files for threats before upload. Doda Browser's download manager uses Drag and Drop for organizing downloads into folders.
flowchart LR A[HTML APIs] --> B[Geolocation API] A --> C[Drag and Drop API] A --> D[File API] B --> E[getCurrentPosition] B --> F[watchPosition] C --> G[dragstart / dragover / drop] C --> H[DataTransfer] D --> I[FileReader] D --> J[File / Blob] D --> K[FileList]
Geolocation API
The Geolocation API provides the user's latitude, longitude, altitude, and heading through the navigator.geolocation object.
// One-time position fetch
function getLocation() {
if (!navigator.geolocation) {
console.error('Geolocation is not supported');
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude, accuracy, altitude, heading, speed } = position.coords;
console.log(`Latitude: ${latitude}`);
console.log(`Longitude: ${longitude}`);
console.log(`Accuracy: ${accuracy}m`);
console.log(`Altitude: ${altitude}m`);
console.log(`Heading: ${heading}deg`);
console.log(`Speed: ${speed}m/s`);
},
(error) => {
switch (error.code) {
case error.PERMISSION_DENIED:
console.error('User denied location request');
break;
case error.POSITION_UNAVAILABLE:
console.error('Location unavailable');
break;
case error.TIMEOUT:
console.error('Location request timed out');
break;
}
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000
}
);
}
getLocation();
Expected output:
Latitude: 40.7128
Longitude: -74.0060
Accuracy: 65m
Altitude: null
Heading: null
Speed: null
Watching Position Changes
For real-time tracking (navigation, fitness apps), use watchPosition.
const watchId = navigator.geolocation.watchPosition(
(position) => {
const { latitude, longitude, heading, speed } = position.coords;
updateMapMarker(latitude, longitude);
if (heading !== null && speed !== null) {
console.log(`Moving ${heading}deg at ${speed}m/s`);
}
},
(error) => console.error('Watch error:', error),
{ enableHighAccuracy: true, timeout: 5000 }
);
// Stop watching
function stopTracking() {
navigator.geolocation.clearWatch(watchId);
console.log('Location tracking stopped');
}
Drag and Drop API
The Drag and Drop API lets users drag elements between zones using dragstart, dragover, drop, and dragend events.
<div id="file-pool" class="drop-zone">
<p>Drop files here</p>
</div>
<ul id="file-list">
<li draggable="true" data-type="image">screenshot.png</li>
<li draggable="true" data-type="document">report.pdf</li>
<li draggable="true" data-type="image">photo.jpg</li>
<li draggable="true" data-type="code">script.js</li>
</ul>
<div id="image-zone" class="drop-zone">Image Files</div>
<div id="doc-zone" class="drop-zone">Documents</div>
const draggables = document.querySelectorAll('[draggable="true"]');
const dropZones = document.querySelectorAll('.drop-zone');
// Drag source events
draggables.forEach(item => {
item.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', item.textContent);
e.dataTransfer.setData('type', item.dataset.type);
item.classList.add('dragging');
});
item.addEventListener('dragend', (e) => {
item.classList.remove('dragging');
});
});
// Drop target events
dropZones.forEach(zone => {
zone.addEventListener('dragover', (e) => {
e.preventDefault();
zone.classList.add('drag-over');
});
zone.addEventListener('dragleave', () => {
zone.classList.remove('drag-over');
});
zone.addEventListener('drop', (e) => {
e.preventDefault();
zone.classList.remove('drag-over');
const type = e.dataTransfer.getData('type');
const name = e.dataTransfer.getData('text/plain');
if (zone.id === 'image-zone' && type === 'image') {
zone.innerHTML += `<div>${name}</div>`;
} else if (zone.id === 'doc-zone' && type === 'document') {
zone.innerHTML += `<div>${name}</div>`;
} else {
alert(`Cannot drop ${name} here`);
}
});
});
Expected behavior: Dragging "screenshot.png" (type: image) over the Image zone highlights it. Dropping adds it to the zone. Dropping a document on the Image zone shows an alert.
File API
The File API lets web applications read files selected by the user or dropped onto the page.
<input type="file" id="file-input" multiple accept="image/*,.pdf,.txt">
<div id="file-output"></div>
const fileInput = document.getElementById('file-input');
const output = document.getElementById('file-output');
fileInput.addEventListener('change', (e) => {
const files = e.target.files;
output.innerHTML = '';
for (const file of files) {
const fileInfo = document.createElement('div');
fileInfo.className = 'file-info';
fileInfo.innerHTML = `
<strong>${file.name}</strong><br>
Size: ${(file.size / 1024).toFixed(1)}KB<br>
Type: ${file.type || 'unknown'}<br>
Last modified: ${new Date(file.lastModified).toLocaleDateString()}
`;
output.appendChild(fileInfo);
}
});
Reading File Contents
Use FileReader to read text, data URLs, or ArrayBuffers.
function readFileAsText(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
reader.readAsText(file);
});
}
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);
});
}
async function processFile(file) {
if (file.type.startsWith('image/')) {
const dataUrl = await readFileAsDataURL(file);
const img = document.createElement('img');
img.src = dataUrl;
img.style.maxWidth = '200px';
document.body.appendChild(img);
} else if (file.type === 'text/plain') {
const text = await readFileAsText(file);
const lines = text.split('\n');
console.log(`File has ${lines.length} lines`);
console.log('First 5 lines:', lines.slice(0, 5).join('\n'));
}
}
fileInput.addEventListener('change', async (e) => {
for (const file of e.target.files) {
await processFile(file);
}
});
Expected output for a text file:
File has 142 lines
First 5 lines: # Configuration file
# Doda Browser settings
homepage = "https://dodatech.com"
theme = "dark"
sidebar = true
File Drag-and-Drop Integration
Combine Drag and Drop with the File API for a complete drop-to-upload interface.
const dropZone = document.getElementById('file-pool');
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('active');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('active');
});
dropZone.addEventListener('drop', async (e) => {
e.preventDefault();
dropZone.classList.remove('active');
const files = e.dataTransfer.files;
if (files.length === 0) return;
const fileList = document.getElementById('file-list');
fileList.innerHTML = '';
for (const file of files) {
const li = document.createElement('li');
li.textContent = `${file.name} (${(file.size / 1024).toFixed(1)}KB)`;
if (file.type.startsWith('image/')) {
const dataUrl = await readFileAsDataURL(file);
const img = document.createElement('img');
img.src = dataUrl;
img.style.width = '50px';
img.style.height = '50px';
img.style.objectFit = 'cover';
li.prepend(img);
}
fileList.appendChild(li);
}
console.log(`Dropped ${files.length} file(s)`);
});
Expected behavior: Dragging a set of files from the desktop onto the drop zone displays thumbnail previews for images and file names with sizes for all files.
Threat Scanner Integration
Combine all three APIs for a practical security scanning tool.
class LocalFileScanner {
constructor() {
this.dropZone = document.getElementById('scan-zone');
this.threatPatterns = [/\.exe$/i, /\.scr$/i, /\.vbs$/i];
this.setupDrop();
this.setupGeolocation();
}
setupDrop() {
this.dropZone.addEventListener('dragover', (e) => e.preventDefault());
this.dropZone.addEventListener('drop', async (e) => {
e.preventDefault();
const files = Array.from(e.dataTransfer.files);
this.scanFiles(files);
});
}
setupGeolocation() {
navigator.geolocation.getCurrentPosition(
(pos) => {
this.location = {
lat: pos.coords.latitude,
lng: pos.coords.longitude
};
console.log('Scan location logged:', this.location);
},
() => { this.location = null; }
);
}
async scanFiles(files) {
const results = [];
for (const file of files) {
const text = await readFileAsText(file);
const score = this.calculateRiskScore(file, text);
results.push({ file, score });
}
this.displayResults(results);
}
calculateRiskScore(file, content) {
let score = 0;
if (this.threatPatterns.some(p => p.test(file.name))) score += 50;
if (content.includes('eval(') || content.includes('exec(')) score += 30;
if (content.includes('base64') && content.length > 10000) score += 20;
return Math.min(score, 100);
}
displayResults(results) {
results.forEach(r => {
const severity = r.score > 50 ? 'High' : r.score > 20 ? 'Medium' : 'Low';
console.log(`${r.file.name}: ${severity} risk (${r.score}/100)`);
});
}
}
const scanner = new LocalFileScanner();
Common Errors
- Geolocation only works on HTTPS — Modern browsers block geolocation on insecure origins. Use
localhostfor development or deploy to HTTPS. - Missing
e.preventDefault()in dragover — Without preventing the default, the browser refuses the drop. Always calle.preventDefault()in bothdragoveranddrophandlers. - FileReader not checking file.type — Users can select any file type regardless of the
acceptattribute. Always validatefile.typebefore processing. - Memory limits with large files — Reading multi-GB files into memory crashes the tab. For large files, use
File.slice()to read in chunks or use the Streams API. - Drag data not available in drop event —
dataTransfer.getData()only works during drop, not in dragover. Access it only when the drop fires. - Not handling permission denial for geolocation — Users can deny geolocation. Always handle the error callback and degrade gracefully, showing manual location input.
Practice Questions
Challenge
Build a secure file upload dashboard that: uses Drag and Drop to accept files; reads the first 64KB of each file to detect magic bytes (file signatures); checks file type against an allow-list; shows a preview for images and a text snippet for documents; logs the upload location via geolocation; and reports file statistics (count, total size, types).
Real-World Task
Extend Durga Antivirus Pro's local file scanner. Users should be able to drag files onto the application's web dashboard, see file metadata (name, size, type, last modified), and trigger a local scan. Read the file content with FileReader, check for suspicious patterns (e.g., eval, base64 payloads, known malware signatures), and display a risk score per file. Log the scan location via geolocation for audit trails.
Previous: JavaScript Fundamentals | Next: Web Workers for File Processing | Related: File API Reference
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro