Detecting browser capabilities is essential for building resilient PWAs. Use feature detection rather than browser sniffing.
// Comprehensive feature detection
const pwaSupport = {
serviceWorker: 'serviceWorker' in navigator,
manifest: document.querySelector('link[rel="manifest"]') !== null,
notifications: 'Notification' in window,
push: 'PushManager' in window,
sync: 'SyncManager' in window,
cache: 'caches' in window,
indexedDB: 'indexedDB' in window,
webShare: navigator.share !== undefined,
webShareTarget: 'shareTarget' in (document.querySelector('link[rel="manifest"]') || {}),
badging: navigator.setAppBadge !== undefined,
credentials: 'credentials' in navigator,
storage: navigator.storage !== undefined,
connection: navigator.connection !== undefined,
wakeLock: 'wakeLock' in navigator,
screenWakeLock: 'wakeLock' in navigator,
bluetooth: navigator.bluetooth !== undefined,
usb: navigator.usb !== undefined,
nfc: 'NDEFReader' in window,
fileSystemAccess: 'showDirectoryPicker' in window,
screenOrientation: screen.orientation !== undefined,
clipboard: navigator.clipboard !== undefined,
contacts: 'contacts' in navigator,
geolocation: 'geolocation' in navigator,
mediaDevices: navigator.mediaDevices !== undefined,
internationalization: Intl !== undefined
};
// Use detection to show/hide features
if (pwaSupport.webShare) {
document.getElementById('share-button').hidden = false;
}
Detect the user's platform to provide platform-specific enhancements:
// Platform detection
const platform = {
isAndroid: /android/i.test(navigator.userAgent),
isIOS: /iphone|ipad|ipod/i.test(navigator.userAgent),
isWindows: /windows nt/i.test(navigator.userAgent),
isMacOS: /macintosh|mac os x/i.test(navigator.userAgent),
isLinux: /linux/i.test(navigator.userAgent),
isChromeOS: /cros/i.test(navigator.userAgent),
isMobile: /mobile|android|iphone|ipad/i.test(navigator.userAgent),
isStandalone: window.matchMedia('(display-mode: standalone)').matches
|| window.navigator.standalone === true,
isInstalled: window.matchMedia('(display-mode: standalone)').matches
|| window.navigator.standalone === true
};
// Platform-specific adjustments
if (platform.isIOS) {
// Add iOS-specific meta tags
document.head.innerHTML += `
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
`;
}
if (platform.isStandalone) {
// The app is running in standalone mode (installed)
document.body.classList.add('is-installed');
}
async function shareContent(title, text, url) {
if (navigator.share) {
try {
await navigator.share({ title, text, url });
console.log('Shared successfully');
} catch (err) {
console.error('Share failed:', err);
}
} else {
// Fallback: copy to clipboard
await navigator.clipboard.writeText(url);
alert('Link copied to clipboard!');
}
}
// Store credentials
async function storeCredentials(email, password) {
if ('credentials' in navigator) {
const cred = new PasswordCredential({
id: email,
password: password,
name: 'My PWA'
});
await navigator.credentials.store(cred);
}
}
// Auto-fill credentials
async function autoSignIn() {
if ('credentials' in navigator) {
const cred = await navigator.credentials.get({
password: true,
mediation: 'optional'
});
if (cred) {
// Auto-fill the login form
document.getElementById('email').value = cred.id;
document.getElementById('password').value = cred.password;
}
}
}