Yugen UI

HTTP status pages

404, 500, maintenance, offline: when a whole page can't render, say what happened, offer one next step and recover on its own when it can, in the same layout as the boot loading screen.

When a page of its own

A status page replaces the whole main content, so use it only when the whole route can't render: nothing at this URL, no permission, a server error, offline when the page opens. When only part of a page fails, report it in that part and keep the rest usable.

CaseUse
The whole route can't renderStatus page
One region fails to load (table, chart)ErrorState in that region, with retry
A form fails to submitErrors on each field or a MessageBar; keep what was typed
A brief error that clears itselfToast or MessageBar

Lab

Eleven states in the same layout as the boot loading screen. Switch numerals (Kanji / Latin), replay, or go full screen and step through states with previous / next.

Page not found

Nothing lives at this URL.

Status catalog

CodeTitleWhenMain action
400Bad requestURL parameters or submitted data are malformed and can't be fixed in place.Go back
401Sign in to continueNot signed in, or the session expired.Sign in
403No accessSigned in, but without permission.Request access
404Page not foundNothing lives at this URL.Search
410This page was removedRemoved on purpose; link to the replacement when there is one.Go to the new page
429That was a bit fastRate limit reached; take the wait from the Retry-After header.Retry
500Something went wrong on our sideAn unexpected server error, including a 502 from a gateway.Retry
503Down for maintenancePlanned maintenance or temporary overload; count down when there is a Retry-After.Reload
504The server took too longTimed out at the server (504) or in the browser (408).Retry
OfflineYou're offlineThe browser lost its connection or a request failed on the network; listen for the online event to retry.Retry
New versionA new version is availableA JS file fails to load after a deploy (a tab opened earlier, file names changed).Reload

Writing the copy

The title says what happened in plain words (“Page not found”); the description says why, when known, and what people can do next. The code sits in the small line above the title for anyone reporting the problem, and is never the only text on the page.

Don't blame the user, don't joke when they just lost what they were doing, don't print a stack trace. An error ID (7f3a-91c2) is plain text people can select and copy.

Each page has exactly one main action; the secondary action is a safe way out, such as Home or Switch account.

Mark & vertical code

The mark in the corner changes with the state: one petal missing when the page isn't found, all fallen when it was removed, still a bud when you need to sign in or ask for access, the ink broken on a server error, faded on a timeout, only a trace when offline. On 429 and 503 the brush stroke fills with the wait; when time is up the blossom opens as Retry turns on.

Kanji style: the code runs down the edge like the loading screen, read digit by digit (四〇四); states without a code use words: 圏外 (out of range) when offline, 新版 for a new version. Latin style, for products that don't use kanji: the code sits horizontally in a light weight in the top corner; states without a code leave that corner empty.

Recovering on its own

Temporary states should clear themselves: count down from Retry-After and then enable the button, listen for the online event to retry, and offer a reload when a JS file fails to load after a deploy. After sign-in (401), take people back to the page they were opening.

// 429 / 503: take the wait from the header, don't guess
const wait = Number(response.headers.get("Retry-After")) || 30;

// Offline: retry when the browser reports a connection
window.addEventListener("online", retry, { once: true });

// New version: the route's JS file is gone after a deploy
const Settings = lazy(() => import("./pages/Settings").catch(() => ({ default: NewVersionPage })));

A 404 page should return a real 404 status and noindex, so search engines don't index a page that looks normal. Static hosts (GitHub Pages) can only serve 404.html; there, 500 and 503 come from the app itself.

Accessibility

The title is an h1 naming the state; on client-side navigation, move focus to the h1 and update document.title. The vertical code is decorative (aria-hidden); the readable code is in the line above the title.

Announce countdowns through a polite live region at intervals (10 seconds), not every second. Never reload on your own without saying so first. With reduced motion, the brush stroke is already drawn and the petals already lie on the ground.

Do and don't

Do
  • Say what happened in plain words, with the code in a secondary line.
  • One main action and one safe way out.
  • Count down from Retry-After; retry when back online.
  • Return a real HTTP status and noindex on 404 pages.
Don't
  • Send unknown URLs to the home page as if nothing happened.
  • Show only “404” or “Error” without an explanation.
  • Print stack traces or technical messages to users.
  • Reload in a loop while the server is still failing.