01 — Purpose

Resilient by default

Progressive enhancement ships a working baseline first — then layers capability. The browser already solves most interaction problems; rebuilding them in JavaScript is usually waste.

Networks fail. JavaScript errors. Extensions block scripts. Start with semantic HTML, server-rendered content, and native forms — then enhance where it genuinely helps.

Custom selects, dialog libraries, and menu systems must justify their cost in maintenance, accessibility, performance, and bundle size against what dialog, popover, links, and native validation already provide.

See semantic HTML, buttons vs links, and modal / dialog.

02 — Platform

Use the platform before you rebuild

Native-first does not mean never using frameworks — it means understanding what the platform already solves.

Modern CSS (Grid, Flexbox, layers, container queries, logical properties) removes many historical workarounds — see cascade layers and container queries.

  • forms — validation, submission, accessible controls without a wrapper library
  • dialogs and popovers — focus behaviour the platform owns
  • navigation — real links, history, keyboard activation
  • media, lazy loading, reduced motion, and semantic structure — before custom layers

When you replace platform behaviour, document why native options failed and prove keyboard, assistive technology, and mobile behaviour match user expectations.

03 — Principles

Enhancement improves — it does not invent

Enhancement should improve functionality — not invent it entirely.

  • semantic HTML first — real links, buttons, forms, headings
  • layered enhancement — CSS, then unobtrusive JS, then richer client behaviour
  • resilient forms — submit and validate server-side; enhance client-side
  • accessible defaults — keyboard and AT work before JS runs

04 — Practice

Good progressive enhancement

Core paths work without JavaScript; enhancement adds speed and polish.

05 — Avoid

Fragile JS-only interfaces

Custom replacements often break accessibility and performance first — delayed render, hydration cost, broken keyboard paths.

  • JS-only interfaces — blank shell until bundle loads
  • dependency-heavy rendering — entire app requires React/Vue to read a paragraph
  • fragile interaction assumptions — div buttons, custom routing with no href fallback
  • client-only data fetching for public content — SEO and no-JS users lose access
  • skipping server validation — client-only checks that fail open

06 — Close

Baseline first, enhance second

If the page fails with JS off, the architecture is wrong for the content.

Define critical paths that must work without script. Enhance them — do not replace them. This site follows that model: static content, a button-controlled mobile menu with links in nav, and targeted client scripts for nav polish and syntax highlighting. Do not use details / summary for the primary site navigation — it breaks desktop layout.

See browser capability strategy, JS module architecture, hydration costs, and JavaScript standard.