LessonLesson 28 of 34

Browser APIs, permissions, and progressive enhancement

Separate HTML from browser capabilities and design permission requests, secure-context requirements, and fallback workflows responsibly.

Advanced5 min readLearn · Practice · Review

Published by HTML Code Runner · AI-assisted material · Independent editorial review pending · Editorial policy

On this page

Learning objectives

Distinguish markup from JavaScript APIs; feature-detect capabilities; design for permission denial, unavailable devices, and offline conditions.

Prerequisites

Understand HTML structure, basic JavaScript promises and events, origins, and the difference between local files and HTTP pages.

HTML is the interface foundation

HTML provides the document and native controls. JavaScript can call browser APIs for capabilities such as location, storage, clipboard access, media devices, workers, or network communication. These features are often discussed beside HTML, but they are not all HTML elements or one single HTML5 permission bundle.

Each API has its own support, security, permission, and lifecycle rules. A feature may exist in the browser but be unavailable in the current context. An embedded page may face additional Permissions Policy restrictions, and a privacy setting may deny an operation. Checking whether a property exists is the beginning of feature detection, not proof that every call will succeed.

Ask when the user understands the benefit

Permission prompts should follow an understandable action. A Find nearby libraries button can explain why location would help and offer a manual postcode alternative. Requesting location immediately on page load gives the person little context and can make a permanent denial more likely.

Geolocation requires a secure context in normal production use and user permission. Handle success, denial, unavailable position, and timeout separately enough to offer a useful next step. Do not claim an exact location from a result whose accuracy is broad. Collect and retain only what the task needs, and explain if information will be sent to a server.

Clipboard, media capture, and other powerful features may require a secure context or a recent user activation. Requirements vary, so consult the specific API documentation and test your supported browsers. A failed call should produce a recoverable explanation, not an uncaught error or a button that silently stops working.

Keep the essential task available

Progressive enhancement starts with a useful base experience and adds capabilities when they are available. A map can have a textual address; a location lookup can accept a manually entered place; a copy button can leave selectable source text visible. These alternatives also help when scripts fail for reasons unrelated to browser support.

Workers can move appropriate computation off the main thread, but they cannot directly manipulate the page DOM. Network APIs have origin and CORS rules that cannot be solved by adding arbitrary client headers. A service worker can support caching strategies, but a poorly designed cache can serve stale or private content. Treat each advanced capability as a design responsibility rather than a checklist item.

Working example

<button type="button" id="check-capability">Check available capabilities</button>
<p id="capability-result" role="status"></p>
<p>You can always enter your location manually.</p>
<label for="manual-place">Town or postcode</label>
<input id="manual-place" name="place" autocomplete="postal-code">

Another example

<button type="button" id="locate">Check my approximate location</button>
<p id="location-status" role="status">Optional: the result stays on this page.</p>
<script>
const status = document.querySelector("#location-status");
document.querySelector("#locate").addEventListener("click", () => {
  if (!("geolocation" in navigator)) { status.textContent = "Location is unavailable. Enter a town instead."; return; }
  navigator.geolocation.getCurrentPosition(
    position => { status.textContent = "Reported accuracy: " + Math.round(position.coords.accuracy) + " metres. No result was sent to a server."; },
    () => { status.textContent = "Location could not be obtained. Enter a town instead."; },
    { timeout: 10000, maximumAge: 60000 }
  );
});
</script>

Expected output

The live example checks whether the geolocation interface is exposed and reports the secure-context state without requesting location. It deliberately avoids a permission prompt. Interface presence alone does not establish permission or guarantee a successful lookup.

Common mistakes

Do not label every browser API an HTML tag. Do not request sensitive capabilities automatically merely because they are available. Do not treat a denied permission as a software bug or keep repeatedly prompting without a new user action.

Accessibility and browser notes

Feedback belongs in readable text and should not depend on a map marker alone. Keep manual alternatives keyboard accessible. Test denied permissions, offline mode, missing devices, and the sandbox restrictions of your embedding context.

Practice

Write a capability check that leaves a manual alternative visible when geolocation is absent.

Review the solution and reasoning
const status = document.querySelector("#location-status");
if (!("geolocation" in navigator)) {
  status.textContent = "Location lookup is unavailable. Enter your town or postcode instead.";
}

The check describes the limitation and gives an actionable alternative. It does not request permission or transmit data. A complete location feature must also handle errors after a request begins.

Related lessons

Specifications and further reading

One more skill in your toolkit.

Finished the explanation and exercise? Save your progress.