Home/Learn/JavaScript & TypeScript/Useful Browser APIs

Useful Browser APIs

Intermediate
The Browser

Clipboard, 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, crypto, matchMedia
// 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.

Ask on a gesture, handle refusal
// 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.

Real parallelism, with no DOM
// 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 after

Key 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 Aria
1

How do you detect that a user prefers dark mode, and react when they change it?

Easy
2

Why should you not request notification permission when the page loads?

Medium
3

When would you use a Web Worker, and what can it not do?

Medium

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.

Loading discussion…