Networks fail all the time. Designing messages, buttons, and logs around API errors keeps users from feeling lost. The essentials for this chapter are “error state message + retry button + backoff order”; online/offline events are optional extras.
Key terms
- Error state: the dedicated screen or panel shown when a data request fails.
- Retry UX: the flow that defines when and how a user retries after a failure.
- Backoff: the strategy of increasing wait times after each failure to avoid hammering the server.
role="alert": an attribute that tells screen readers to announce the region immediately.online/offlineevents: browser events that reveal network changes so you can toggle UI states accordingly.
Core ideas
- Error state: a failure view that includes a message, icon, and retry action whenever data is missing or requests fail.
- Retry UX: spell out delay intervals, backoff rules, and retry counts so users can recover gracefully.
- Error categories: distinguish network issues, server errors, and user input errors to deliver targeted messages.
- Logging and toasts: send details to monitoring while showing concise toasts for end users.
Error flow diagram
In words: “user request → API failure → UI shows a message and logs → user clicks retry → API request again.” Define what the UI must do at every failure point.
Basic error handling
Before tackling retries, keep the simplest state display in mind.
setStatus("Loading");
showRetry(false);
// On failure call setStatus("Please try again shortly")
Every complex flow still relies on two toggles: the status text and whether the retry button is visible.
How to retry failed requests
Now combine retry logic with backoff.
const statusBox = document.querySelector(".status-box");
const retryButton = document.querySelector(".retry-button");
function setStatus(message) {
if (statusBox) statusBox.textContent = message;
}
function showRetry(show) {
if (retryButton) retryButton.classList.toggle("is-hidden", !show);
}
async function fetchTasks({ retries = 3, delayMs = 500 } = {}) {
let attempt = 0;
while (attempt < retries) {
try {
setStatus(`Loading... (attempt ${attempt + 1})`);
const response = await fetch("/api/tasks");
if (!response.ok) throw new Error(`Server error ${response.status}`);
const data = await response.json();
setStatus("Done");
return data;
} catch (error) {
attempt += 1;
console.error("API failure", error);
if (attempt === retries) {
setStatus("Network is unstable. Please try again in a moment.");
showRetry(true);
throw error;
}
await new Promise((resolve) => setTimeout(resolve, delayMs * attempt));
}
}
}
retryButton?.addEventListener("click", () => {
showRetry(false);
fetchTasks();
});
Backoff simply means the delay grows with each attempt (delayMs * attempt), lightening the load on the server.
Error cards by category
Render targeted messages for each error type.
function showErrorCard({ title, description, action }) {
return `
<div class="error-card" role="alert">
<h3>${title}</h3>
<p>${description}</p>
<button data-action="${action.id}">${action.label}</button>
</div>
`;
}
const errorRoot = document.querySelector("#error-root");
function renderError(type) {
const map = {
offline: {
title: "Offline",
description: "Check your internet connection and try again.",
action: { id: "reload", label: "Reload" },
},
server: {
title: "Server delay",
description: "Try again shortly or contact the admin.",
action: { id: "retry", label: "Retry" },
},
};
if (errorRoot) errorRoot.innerHTML = showErrorCard(map[type]);
}
errorRoot?.addEventListener("click", (event) => {
const button = event.target;
if (!(button instanceof HTMLButtonElement)) return;
if (button.dataset.action === "reload") location.reload();
if (button.dataset.action === "retry") fetchTasks();
});
Predefining categories like offline and server lets you react quickly to error codes coming back from the backend.
Online/offline awareness
Detect network changes to swap UI states automatically.
window.addEventListener("offline", () => {
renderError("offline");
});
window.addEventListener("online", () => {
setStatus("Connected again.");
fetchTasks();
});
online/offline events are optional—attach them after the core retry UX is solid.
Simulating network conditions and errors
Preview failure scenarios quickly with a BrowserMock component.
💬 댓글
이 글에 대한 의견을 남겨주세요