-
-
Notifications
You must be signed in to change notification settings - Fork 2
JavaScript Web APIs
Mattscreative edited this page Feb 21, 2026
·
1 revision
- Introduction
- Navigator API
- Geolocation API
- Clipboard API
- Notifications API
- Web Workers
- Intersection Observer
- Resize Observer
- Beacon API
- Fullscreen API
- Page Visibility API
- Performance API
Web APIs are interfaces provided by browsers that allow JavaScript to interact with browser features and hardware.
The Navigator object contains information about the browser.
// Basic info
console.log(navigator.userAgent); // Browser string
console.log(navigator.platform); // Platform
console.log(navigator.language); // Browser language
console.log(navigator.languages); // Preferred languages
// Connection info
console.log(navigator.onLine); // Is online?
console.log(navigator.connection); // Network connection info
// Device info
console.log(navigator.hardwareConcurrency); // CPU cores
console.log(navigator.deviceMemory); // RAM (if available)
// Cookies
console.log(navigator.cookieEnabled); // Cookies enabled?
// Check features
console.log(navigator.javaEnabled()); // Java enabled?
// Service Workers
console.log(navigator.serviceWorker); // ServiceWorkerContainer// Read from clipboard
async function readClipboard() {
try {
const text = await navigator.clipboard.readText();
console.log('Clipboard:', text);
} catch (err) {
console.error('Failed to read:', err);
}
}
// Write to clipboard
async function writeClipboard(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Copied!');
} catch (err) {
console.error('Failed to copy:', err);
}
}
// Write HTML to clipboard
async function copyHTML(html) {
const blob = new Blob([html], { type: 'text/html' });
const textBlob = new Blob([html], { type: 'text/plain' });
await navigator.clipboard.write([
new ClipboardItem({
'text/html': blob,
'text/plain': textBlob
})
]);
}// Listen for online/offline
window.addEventListener('online', () => {
console.log('Back online!');
// Sync data
});
window.addEventListener('offline', () => {
console.log('Gone offline!');
// Disable features that require network
});// Check if geolocation is available
if ('geolocation' in navigator) {
// Get current position
navigator.geolocation.getCurrentPosition(
(position) => {
console.log('Latitude:', position.coords.latitude);
console.log('Longitude:', position.coords.longitude);
console.log('Accuracy:', position.coords.accuracy, 'meters');
console.log('Altitude:', position.coords.altitude);
console.log('Speed:', position.coords.speed);
},
(error) => {
console.error('Error:', error.message);
},
{
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0 // Don't use cached position
}
);
// Watch position (continuous)
const watchId = navigator.geolocation.watchPosition(
(position) => {
console.log('New position:', position.coords.latitude, position.coords.longitude);
},
(error) => console.error(error),
{ enableHighAccuracy: true }
);
// Stop watching
navigator.geolocation.clearWatch(watchId);
}// Request permission
async function requestNotificationPermission() {
if (!('Notification' in window)) {
console.log('Notifications not supported');
return;
}
const permission = await Notification.requestPermission();
console.log('Permission:', permission);
}
// Show notification
function showNotification(title, options = {}) {
if (Notification.permission === 'granted') {
const notification = new Notification(title, {
body: options.body || '',
icon: options.icon || '/icon.png',
badge: options.badge || '/badge.png',
tag: options.tag || '',
data: options.data,
requireInteraction: options.requireInteraction || false,
actions: options.actions || []
});
notification.onclick = () => {
console.log('Notification clicked');
window.focus();
notification.close();
};
return notification;
}
}
// Example usage
document.getElementById('notifyBtn').addEventListener('click', async () => {
await requestNotificationPermission();
showNotification('Hello!', { body: 'This is a notification' });
});Web Workers run code in a background thread, keeping the main thread responsive.
// Create worker
const worker = new Worker('worker.js');
// Send message to worker
worker.postMessage({ type: 'compute', data: [1, 2, 3, 4, 5] });
// Receive message from worker
worker.onmessage = (event) => {
console.log('Result:', event.data);
};
// Handle errors
worker.onerror = (error) => {
console.error('Worker error:', error.message);
};
// Terminate worker
worker.terminate();// Receive message from main thread
self.onmessage = (event) => {
const { type, data } = event.data;
if (type === 'compute') {
// Do heavy computation
const result = data.reduce((sum, n) => sum + n, 0);
// Send result back
postMessage(result);
}
};
// Or use addEventListener
self.addEventListener('message', (event) => {
// Handle message
});
// Post message to main thread
postMessage({ status: 'done' });
// Error handling
self.onerror = (error) => {
console.error('Error in worker:', error);
};
// Import scripts
importScripts('script1.js', 'script2.js');// Create shared worker
const sharedWorker = new SharedWorker('shared-worker.js');
sharedWorker.port.onmessage = (event) => {
console.log('From shared worker:', event.data);
};
sharedWorker.port.start();
sharedWorker.port.postMessage('Hello from main thread!');Detect when elements enter or leave the viewport.
// Create observer
const observer = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('Element is visible:', entry.target);
// Load content, animate, etc.
} else {
console.log('Element is hidden:', entry.target);
}
});
},
{
root: null, // Use viewport
rootMargin: '0px', // Margin around root
threshold: 0.5 // Trigger when 50% visible
}
);
// Observe element
const element = document.getElementById('lazy-image');
observer.observe(element);
// Stop observing
observer.unobserve(element);
// Disconnect observer
observer.disconnect();const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
}, {
rootMargin: '50px 0px',
threshold: 0.01
});
document.querySelectorAll('img.lazy').forEach(img => {
imageObserver.observe(img);
});// Create observer
const observer = new ResizeObserver((entries) => {
entries.forEach(entry => {
const { width, height } = entry.contentRect;
console.log('Size changed:', width, 'x', height);
// Can also access borderBoxSize, contentBoxSize
});
});
// Observe element
const element = document.getElementById('container');
observer.observe(element);
// Observe multiple
observer.observe(document.querySelectorAll('.box'));
// Stop observing
observer.disconnect();Send data to server reliably, even when page unloads.
// Send beacon
const data = JSON.stringify({ event: 'pageview', url: '/home' });
navigator.sendBeacon('/api/analytics', data);
// With Blob
const blob = new Blob([JSON.stringify({ data: 'example' })], { type: 'application/json' });
navigator.sendBeacon('/api/endpoint', blob);
// Use case: analytics on page unload
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon('/api/analytics', JSON.stringify({
type: 'pagehide',
url: window.location.href
}));
}
});// Request fullscreen
function requestFullscreen(element) {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullscreen) { // Safari
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) { // IE11
element.msRequestFullscreen();
}
}
// Exit fullscreen
function exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}
// Check if fullscreen
function isFullscreen() {
return !!(
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.msFullscreenElement
);
}
// Listen for changes
document.addEventListener('fullscreenchange', () => {
console.log('Fullscreen changed:', !!document.fullscreenElement);
});
// Toggle fullscreen
function toggleFullscreen(element) {
if (isFullscreen()) {
exitFullscreen();
} else {
requestFullscreen(element);
}
}Detect when page is visible, hidden, or minimized.
// Check current state
console.log(document.visibilityState); // 'visible', 'hidden', 'prerender', 'unloaded'
// Listen for changes
document.addEventListener('visibilitychange', () => {
console.log('Visibility changed:', document.visibilityState);
if (document.hidden) {
console.log('Page is hidden - pause animations, stop polls');
} else {
console.log('Page is visible - resume');
}
});
// Practical use: stop polling when hidden
let pollInterval;
function startPolling() {
pollInterval = setInterval(() => {
// Fetch data
}, 5000);
}
function stopPolling() {
clearInterval(pollInterval);
}
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
stopPolling();
} else {
startPolling();
}
});// Navigation timing
const [navigation] = performance.getEntriesByType('navigation');
console.log('Page load time:', navigation.loadEventEnd - navigation.fetchStart);
console.log('DNS lookup:', navigation.domainLookupEnd - navigation.domainLookupStart);
console.log('TCP connect:', navigation.connectEnd - navigation.connectStart);
console.log('Response:', navigation.responseEnd - navigation.responseStart);
console.log('DOM content:', navigation.domContentLoadedEventEnd - navigation.fetchStart);
console.log('Page render:', navigation.loadEventEnd - navigation.fetchStart);
// Resource timing
performance.getEntriesByType('resource').forEach(resource => {
console.log(resource.name, resource.duration);
});
// Custom marks
performance.mark('start');
function doSomething() {
performance.mark('end');
performance.measure('doSomething', 'start', 'end');
}
// Clear marks
performance.clearMarks();
performance.clearMeasures();// Mark specific points
performance.mark('pageStart');
performance.mark('scriptsLoaded');
performance.mark('pageComplete');
// Measure between marks
performance.measure('pageLoad', 'pageStart', 'pageComplete');
// Get measurements
const measures = performance.getEntriesByType('measure');
measures.forEach(measure => {
console.log(measure.name, measure.duration);
});// Navigator
navigator.userAgent
navigator.onLine
navigator.language
// Geolocation
navigator.geolocation.getCurrentPosition(success, error, options)
// Clipboard
navigator.clipboard.readText()
navigator.clipboard.writeText(text)
// Notifications
Notification.requestPermission()
new Notification(title, options)
// Web Workers
new Worker(url)
worker.postMessage(data)
worker.onmessage = (e) => { }
// Intersection Observer
new IntersectionObserver(callback, options)
observer.observe(element)
// Performance
performance.now()
performance.mark(name)
performance.measure(name, startMark, endMark)
// Page Visibility
document.visibilityState
document.hidden
// Fullscreen
element.requestFullscreen()
document.exitFullscreen()
document.fullscreenElement