Useful Browser APIs
IntermediateClipboard, geolocation, notifications, media queries, crypto and Web Workers — the built-ins worth knowing before reaching for a library.
Overview
A large amount of what people install packages for is already in the browser. Copying to the clipboard is one call. Random IDs are one call. Detecting dark mode is a media query you can read from JavaScript and subscribe to. Knowing this list saves bundle size and dependencies. The important shared idea is permissions: anything privacy-sensitive requires a user gesture and an explicit grant, and you must handle refusal.
Clipboard, Crypto, Media Queries
Three small APIs that replace common dependencies.
// Clipboard — requires a user gesture and a secure context
await navigator.clipboard.writeText(code)
const text = await navigator.clipboard.readText() // needs permission
// Crypto — proper random, no library needed
crypto.randomUUID() // 'a3f8...' RFC 4122 v4
crypto.getRandomValues(new Uint8Array(16))
// Media queries from JavaScript, including live changes
const dark = window.matchMedia('(prefers-color-scheme: dark)')
dark.matches // boolean now
dark.addEventListener('change', e => applyTheme(e.matches))
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)')
if (!reduced.matches) animate()Permissions and Gestures
Anything sensitive needs asking, and can be refused — permanently. Ask at the moment the user wants the feature, not on page load.
// Notifications — never request on load; you will be blocked forever
button.addEventListener('click', async () => {
const result = await Notification.requestPermission()
if (result === 'granted') new Notification('Daily challenge ready')
})
// Geolocation — callback based, and always handle refusal
navigator.geolocation.getCurrentPosition(
pos => setCity(pos.coords),
err => setCity(null), // denied or unavailable
{ timeout: 5000 },
)
// Checking without prompting
const status = await navigator.permissions.query({ name: 'notifications' })
status.state // 'granted' | 'denied' | 'prompt'Web Workers
The only way to get real parallelism in the browser. Use it when CPU work would otherwise freeze the page.
// worker.js
self.onmessage = (e) => {
const result = expensiveComputation(e.data)
self.postMessage(result)
}
// main thread
const worker = new Worker(new URL('./worker.js', import.meta.url), {
type: 'module',
})
worker.postMessage(input)
worker.onmessage = (e) => setResult(e.data)
worker.terminate()
// Workers have no DOM access. Data is structured-cloned across the
// boundary, so large payloads cost — or transfer ownership:
worker.postMessage(buffer, [buffer]) // zero-copy, buffer unusable here afterKey Points to Remember
- 1crypto.randomUUID() and navigator.clipboard.writeText() replace common dependencies with one call each
- 2matchMedia reads media queries from JavaScript and fires on change — the correct way to react to dark mode
- 3Permission prompts need a user gesture; requesting notifications on page load gets you permanently blocked
- 4Always handle permission refusal — a denied prompt cannot be re-asked
- 5Web Workers give genuine parallelism but have no DOM access, and data is copied across the boundary unless transferred
Interview Questions
Sign in to ask AriaHow do you detect that a user prefers dark mode, and react when they change it?
Why should you not request notification permission when the page loads?
When would you use a Web Worker, and what can it not do?
Ask Aria about Useful Browser APIs
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.