Put essential content and real navigation in the delivered HTML, then add JavaScript where it improves the experience. Define a truthful fallback for each important task. Progressive enhancement does not require identical behavior in every browser; it requires a useful baseline and careful handling when an enhancement is unavailable.
Which parts of a business website should work first?
List the core tasks: reading a service description, finding business details, moving between pages, opening a relevant download, and choosing a contact route. These are often possible with ordinary HTML links, text, and controls. A filtering interface, live estimate, or embedded scheduling tool may be an enhancement with additional dependencies.
Write a baseline promise for each component. For example: “The service-area directory remains readable and every location link works without the filter.” That is testable. “The site works without JavaScript” is too broad unless you have defined what every feature means.
Some applications genuinely require JavaScript for their central function. Explain that requirement and offer an appropriate recovery path; do not pretend a static fallback can replace a complex interactive system. The static website versus web app guide helps set that scope.
What does an HTML-first implementation look like?
Use anchors with actual destinations for navigation and native buttons for actions. Put important content in the initial HTML instead of fetching and injecting every paragraph after load. Keep headings and labels meaningful before scripts execute.
Avoid hiding the entire page or navigation until initialization completes. If the initialization script fails, that pattern can leave an empty screen or no route out. For a collapsible navigation, define a usable default and expose the toggle only after the component’s behavior is ready.
HTML-first is not the same as unstyled. CSS can provide layout and readable presentation while the underlying content and destinations remain usable. Semantic markup also supports assistive technology, but this approach alone does not establish complete accessibility.
How can a directory filter remain optional?
Example: a service-area directory
Render all locations as a normal list of links. Keep an optional filter control hidden initially. The script finds the required elements, attaches the filter behavior, and only then reveals the control. If the script never loads, the full directory stays visible.
<div id="filter-panel" hidden>
<label for="area-filter">Filter locations</label>
<input id="area-filter" type="search">
</div>
<ul id="areas">
<li><a href="/areas/north/">North area</a></li>
<li><a href="/areas/south/">South area</a></li>
</ul>
<p id="filter-status" aria-live="polite"></p>The addresses above are illustrative; use real destinations on your site. A small local script can enhance that markup:
const panel = document.querySelector('#filter-panel');
const input = document.querySelector('#area-filter');
const list = document.querySelector('#areas');
const status = document.querySelector('#filter-status');
if (panel && input && list && status) {
const items = [...list.querySelectorAll('li')];
input.addEventListener('input', () => {
const query = input.value.trim().toLowerCase();
let count = 0;
for (const item of items) {
item.hidden = !item.textContent.toLowerCase().includes(query);
if (!item.hidden) count += 1;
}
status.textContent = `${count} ${count === 1 ? 'location' : 'locations'} shown`;
});
panel.hidden = false;
}Save the JavaScript as /assets/js/area-filter.js and load it with <script src="/assets/js/area-filter.js" defer></script> on the page. Adjust that root-relative path if the site is hosted under a project prefix. Clearing the field restores all entries. Keep the filter small and understandable; this example does not implement ranked search, remote results, or every localization need. Test the result announcement and focus behavior with the technologies your audience uses.
Can every form fall back to a normal HTML submission?
Only if its real endpoint accepts the form’s method and encoding and returns a useful result. A native form commonly submits URL-encoded or multipart data; an endpoint that accepts only JSON is not automatically compatible. A JavaScript success message is not a fallback submission path.
If the form provider or anti-spam protection needs JavaScript, keep an appropriate alternate contact option visible. Do not remove server-side validation, spam protection, or access controls just to make a no-JavaScript demo pass. An email or telephone link offers another route, but opening it does not prove a message or call was completed.
See the static contact form guide for actual delivery tests. For live data that enhances a page, the safe API integration guide covers truthful loading and failure states.
Which failure cases should you test?
- JavaScript disabled: reload and attempt each baseline task.
- Main script blocked: use a controlled browser test to simulate a failed download.
- Optional vendor blocked: verify a chat, map, or booking outage does not disable unrelated navigation.
- Slow loading: interact before enhancements finish initializing.
- API failure: return a controlled error and verify the fallback wording.
- Initialization failure: test on a development branch and confirm unfinished controls do not trap the visitor.
- Repeated navigation: test keyboard interaction, direct URLs, Back, and returning to the page.
A <noscript> message can explain disabled or unsupported scripting. It does not appear automatically when JavaScript is enabled but a script throws an error. Design runtime failure handling separately.
What should you record as a release condition?
Record the component, baseline task, enhancement, simulated failure, expected fallback, and actual result. The directory example should show every location when scripts are disabled, expose a working filter when initialization succeeds, and keep navigation useful during an unrelated widget failure.
Do not reduce the acceptance condition to a clean Console. A page can have no error messages and still hide the only contact option. Combine automated checks for known conditions with human testing of the important customer journeys.
Use the launch checklist for the broader release. The accessibility checklist adds keyboard, labeling, contrast, and zoom considerations beyond failure resilience.
Sources and further reading
- MDN: Progressive enhancement
- MDN: The form element
- MDN: The noscript element
- Chrome DevTools: Disable JavaScript
Documentation checked October 6, 2026. Examples illustrate a workflow; they are not measured client results or guarantees.
Build on a clear website foundation
This free article extends the beginner workflow with a focused technical topic. If you need the starting process, BUILD • PUBLISH • OWN IT is a 44-page beginner PDF guide for $99.99 USD covering a ChatGPT, GitHub, and Cloudflare website workflow. Review its contents to see what the PDF includes; this article does not promise that every technique here is covered there.
Colby will personally assist if you get stuck following the guide. Additional hands-on work may carry a fee, with the scope and price agreed before work begins. Applicable tax is shown at checkout, and third-party service charges are separate. Read the purchase terms for details.