Advanced HTML5 APIs: Complete Guide with Code Examples
HTML5 is far more than markup. Its browser APIs unlock capabilities that were once only possible in native desktop apps: real-time geolocation, offline storage, GPU-accelerated graphics, background threads, drag-and-drop, file system access, and more. This guide covers the most powerful HTML5 APIs with practical code examples, browser compatibility notes, and real-world use cases — everything you need to build modern, capable web applications.
10+
HTML5 APIs covered
98%
Browser support for core APIs
0
Plugins required
2026
All examples modern & up to date
Geolocation API: Real-Time Location Access
The Geolocation API lets web apps access the device's physical location with user permission. It works via GPS, Wi-Fi triangulation, cellular data, or IP address depending on the device and context.
// Check for browser support first
if (!navigator.geolocation) {
console.error('Geolocation is not supported by this browser');
return;
}
// One-time position request
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude, accuracy } = position.coords;
console.log(`Lat: ${latitude}, Lng: ${longitude}`);
console.log(`Accuracy: ${accuracy} meters`);
},
(error) => {
switch (error.code) {
case error.PERMISSION_DENIED:
console.error('User denied location permission');
break;
case error.POSITION_UNAVAILABLE:
console.error('Location unavailable');
break;
case error.TIMEOUT:
console.error('Request timed out');
break;
}
},
{
enableHighAccuracy: true, // Use GPS when available
timeout: 10000, // Wait up to 10 seconds
maximumAge: 60000, // Cache position for 1 minute
}
);
// Continuous tracking (stop with clearWatch)
const watchId = navigator.geolocation.watchPosition(
(position) => updateMapPosition(position.coords),
handleError,
{ enableHighAccuracy: true }
);
// Stop tracking
navigator.geolocation.clearWatch(watchId);HTTPS Required
Web Storage API: localStorage and sessionStorage
Web Storage provides simple key-value storage in the browser — no cookies needed. It comes in two flavors: localStorage (persists until explicitly cleared) and sessionStorage (cleared when the tab closes).
| Item | localStorage | sessionStorage |
|---|---|---|
| Persistence | Survives browser close/reopen | Cleared when tab/window closes |
| Scope | Shared across all tabs for same origin | Isolated to specific tab |
| Capacity | 5–10 MB (browser-dependent) | 5–10 MB (browser-dependent) |
| Use case | User preferences, auth tokens, cached data | Form state, wizard steps, temp data |
| Access | window.localStorage | window.sessionStorage |
// Save data
localStorage.setItem('theme', 'dark');
localStorage.setItem('user', JSON.stringify({ id: 42, name: 'Alice' }));
// Read data
const theme = localStorage.getItem('theme'); // 'dark'
const user = JSON.parse(localStorage.getItem('user')); // { id: 42, name: 'Alice' }
// Remove a specific item
localStorage.removeItem('theme');
// Clear all localStorage for this origin
localStorage.clear();
// Check storage availability
function isLocalStorageAvailable() {
try {
localStorage.setItem('__test__', '1');
localStorage.removeItem('__test__');
return true;
} catch (e) {
return false; // Incognito mode or storage disabled
}
}
// sessionStorage works the same way but is tab-specific
sessionStorage.setItem('currentStep', '3');
const step = sessionStorage.getItem('currentStep'); // '3'Storage Limits and JSON Serialization
Canvas API: 2D and Animated Graphics
The Canvas API provides a JavaScript-driven drawing surface for 2D graphics, animations, image manipulation, and even basic games. It uses immediate mode rendering — you draw pixels directly, not DOM nodes.
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// Draw a rectangle
ctx.fillStyle = '#4F46E5';
ctx.fillRect(10, 10, 150, 100);
// Draw a circle
ctx.beginPath();
ctx.arc(200, 60, 50, 0, Math.PI * 2);
ctx.fillStyle = '#10B981';
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 3;
ctx.stroke();
// Draw text
ctx.font = 'bold 24px Arial';
ctx.fillStyle = '#1F2937';
ctx.fillText('Hello Canvas!', 10, 160);
// Draw an image
const img = new Image();
img.onload = () => ctx.drawImage(img, 300, 10, 100, 100);
img.src = '/logo.png';
// Animation loop
let x = 0;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear frame
ctx.fillStyle = '#6366F1';
ctx.fillRect(x, 50, 50, 50); // Moving square
x = (x + 2) % canvas.width; // Move right, wrap around
requestAnimationFrame(animate); // Call next frame
}
animate();Web Workers: Background Threading
JavaScript is single-threaded by default — heavy computations block the UI. Web Workers run scripts in a background thread, keeping the main thread (and UI) responsive during intensive tasks like data processing, image manipulation, or complex calculations.
// Create a worker from a separate JS file
const worker = new Worker('/workers/compute.js');
// Send data to the worker
worker.postMessage({ data: largeDataArray, operation: 'sort' });
// Receive results from the worker
worker.onmessage = (event) => {
console.log('Worker result:', event.data);
updateUI(event.data); // Safe to update DOM here (main thread)
};
// Handle worker errors
worker.onerror = (error) => {
console.error('Worker error:', error.message);
};
// Terminate worker when done
worker.terminate();// Web Workers cannot access the DOM
// They have access to: fetch, setTimeout, WebSockets, IndexedDB
self.onmessage = (event) => {
const { data, operation } = event.data;
let result;
if (operation === 'sort') {
result = [...data].sort((a, b) => a - b);
} else if (operation === 'sum') {
result = data.reduce((acc, val) => acc + val, 0);
}
// Send result back to main thread
self.postMessage(result);
};File API: Reading Files in the Browser
const input = document.getElementById('fileInput');
input.addEventListener('change', (event) => {
const file = event.target.files[0];
if (!file) return;
console.log(`Name: ${file.name}, Size: ${file.size} bytes, Type: ${file.type}`);
const reader = new FileReader();
// Read as text (for .txt, .csv, .json files)
reader.readAsText(file);
reader.onload = (e) => {
const content = e.target.result;
console.log('File content:', content);
// Parse JSON if needed
if (file.type === 'application/json') {
const parsed = JSON.parse(content);
processData(parsed);
}
};
reader.onerror = () => console.error('Error reading file');
// For images: read as DataURL
if (file.type.startsWith('image/')) {
const imgReader = new FileReader();
imgReader.readAsDataURL(file);
imgReader.onload = (e) => {
document.getElementById('preview').src = e.target.result;
};
}
});Drag and Drop API
// Make an element draggable
const draggable = document.getElementById('card');
draggable.setAttribute('draggable', 'true');
draggable.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', draggable.id);
e.dataTransfer.effectAllowed = 'move';
draggable.classList.add('opacity-50'); // Visual feedback
});
draggable.addEventListener('dragend', () => {
draggable.classList.remove('opacity-50');
});
// Set up a drop zone
const dropZone = document.getElementById('dropZone');
dropZone.addEventListener('dragover', (e) => {
e.preventDefault(); // Required to allow dropping
e.dataTransfer.dropEffect = 'move';
dropZone.classList.add('bg-blue-100');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('bg-blue-100');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
const id = e.dataTransfer.getData('text/plain');
const element = document.getElementById(id);
dropZone.appendChild(element); // Move element to drop zone
dropZone.classList.remove('bg-blue-100');
});IndexedDB: Client-Side Database
For large-scale client-side storage beyond what localStorage can handle, IndexedDB provides a full asynchronous database engine in the browser. It supports structured data, indexes, transactions, and queries.
// Open (or create) a database
const request = indexedDB.open('myAppDB', 1);
// Create schema on first run or version upgrade
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('users', { keyPath: 'id' });
store.createIndex('email', 'email', { unique: true });
};
request.onsuccess = (event) => {
const db = event.target.result;
// Write a record
const tx = db.transaction('users', 'readwrite');
tx.objectStore('users').put({ id: 1, name: 'Alice', email: 'alice@example.com' });
// Read a record by key
const readTx = db.transaction('users', 'readonly');
const getReq = readTx.objectStore('users').get(1);
getReq.onsuccess = () => console.log('User:', getReq.result);
// Query by index
const emailIndex = readTx.objectStore('users').index('email');
const emailReq = emailIndex.get('alice@example.com');
emailReq.onsuccess = () => console.log('By email:', emailReq.result);
};Intersection Observer: Lazy Loading and Scroll Detection
// Create an observer that fires when elements enter the viewport
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // Load the real image
img.classList.remove('opacity-0');
img.classList.add('opacity-100', 'transition-opacity', 'duration-300');
observer.unobserve(img); // Stop watching once loaded
}
});
},
{
rootMargin: '100px', // Start loading 100px before entering viewport
threshold: 0.1, // Fire when 10% of element is visible
}
);
// Observe all lazy images
document.querySelectorAll('img[data-src]').forEach((img) => {
observer.observe(img);
});Web Notifications API
// Request permission first (must be triggered by user gesture)
async function requestNotificationPermission() {
if (!('Notification' in window)) {
console.log('Browser does not support notifications');
return;
}
const permission = await Notification.requestPermission();
return permission === 'granted';
}
// Send a notification
function sendNotification(title, options = {}) {
if (Notification.permission !== 'granted') return;
const notification = new Notification(title, {
body: options.body || '',
icon: options.icon || '/favicon.ico',
badge: '/badge.png',
tag: options.tag || 'default', // Replaces existing notification with same tag
requireInteraction: false, // Auto-close after a few seconds
data: { url: options.url },
});
notification.onclick = () => {
window.focus();
if (notification.data.url) window.location.href = notification.data.url;
notification.close();
};
}
// Usage
const allowed = await requestNotificationPermission();
if (allowed) sendNotification('New Message', { body: 'You have 3 unread messages', url: '/inbox' });API Browser Compatibility Overview
| Item | HTML5 API | Browser Support (2026) |
|---|---|---|
| Geolocation API | All modern browsers | HTTPS required; ~97% global support |
| localStorage / sessionStorage | Universal support | ~99% global support |
| Canvas 2D API | All modern browsers | ~99% global support |
| Web Workers | All modern browsers | ~97% global support |
| File API | All modern browsers | ~98% global support |
| Drag & Drop API | Chrome, Firefox, Edge, Safari | ~96% (some mobile limitations) |
| IndexedDB | All modern browsers | ~98% global support |
| Intersection Observer | All modern browsers | ~97% global support |
| Web Notifications | Chrome, Firefox, Edge (limited Safari) | ~84%; iOS Safari restricted |
| WebRTC | All modern browsers | ~95% global support |
Check MDN for Live Compatibility Data
Always check permissions
Geolocation, Notifications, and Clipboard APIs require explicit user permission. Always request on user gesture, handle denial gracefully, and never prompt repeatedly.
Progressive enhancement
Check for API support before using it. Provide fallbacks for browsers that lack support. Never assume a feature is available.
Performance considerations
Canvas animations should use requestAnimationFrame, not setInterval. Web Workers prevent main thread blocking. Intersection Observer is more efficient than scroll event listeners.
Security model
Most powerful APIs require HTTPS. APIs like Geolocation and Notifications require user permission. File API cannot access the filesystem without user selection.
Frequently Asked Questions
Summary