PWA Capabilities — Interactive Demo

Dark mode with purple tints — test many features here. Best experience on localhost or HTTPS.

Install / beforeinstallpromptPWA install prompt
unknown

The browser fires a `beforeinstallprompt` event when the PWA is eligible. iOS controls "Add to Home Screen" via share sheet (manual).


// Example: listen for beforeinstallprompt
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  deferredPrompt = e;
  // show your install UI
});
document.getElementById('btnPrompt').addEventListener('click', async () => {
  if(deferredPrompt){ await deferredPrompt.prompt(); let res = await deferredPrompt.userChoice; console.log(res); }
});
    
Service Worker / Offline CachingRequires service-worker.js + HTTPS or localhost
sw: unknown

This demo can attempt to register a temporary worker. For full offline caching, download the provided service-worker.js and serve it from the same folder.


// Simplified service worker caching flow (service-worker.js)
self.addEventListener('install', event => {
  event.waitUntil(caches.open('demo-v1').then(c => c.addAll(['/','/pwa-demo.html'])));
});
self.addEventListener('fetch', e => {
  e.respondWith(caches.match(e.request).then(r => r || fetch(e.request)));
});
    
Storage: localStorage & IndexedDBPersistent storage
localStorage output

IndexedDB demo also included (small wrapper). Use it for larger structured storage.


// localStorage usage
localStorage.setItem('demoKey','demoValue');
let v = localStorage.getItem('demoKey');
    
Camera & MicrophonegetUserMedia
Camera / mic state

// getUserMedia
const stream = await navigator.mediaDevices.getUserMedia({video:true,audio:true});
video.srcObject = stream;
    
GeolocationOne-time location fetch

iOS shows a permission dialog. Background tracking while closed is not available in PWAs on iOS.


// Geolocation
navigator.geolocation.getCurrentPosition(pos => console.log(pos.coords));
    
Notifications & Push (explain)Permission + subscription
perm: ?

Server required for real push. On iOS Safari it uses APNs behind the scenes. Use the provided snippet to subscribe and send a test push from a server.


// client: subscribe (example)
const reg = await navigator.serviceWorker.ready;
const sub = await reg.pushManager.subscribe({userVisibleOnly:true,applicationServerKey: '...VAPID key...'});
// send `sub` to your server and call push via web-push / APNs.
    
Web Share / File Picker / Clipboardshare text/files
Share output

// Web Share
if(navigator.canShare) await navigator.share({title:'Hello',text:'Share from demo'});
    
Vibration / Haptics & Mediavibrate, media playback

// Vibration
navigator.vibrate([200,100,200]);
    
Bluetooth & WebUSB (notes)very limited on iOS
Most iOS builds restrict Web Bluetooth; Desktop Chrome gives best experience.

// Web Bluetooth (desktop Chromium)
// const dev = await navigator.bluetooth.requestDevice({filters:[{services:['battery_service']}]});
    
WebSocket test (echo)connect to public echo (if allowed)
disconnected
ws messages

// WebSocket simple
// const ws = new WebSocket('wss://echo.websocket.org/');
// ws.onmessage = e => console.log(e.data);