DEV3 Technologies home

404 page with search

A friendly not-found page with a large status code, a search form that falls back to a plain GET request and helpful links.

Tailwind CSSLayouts404error-pagesearchnot-found

Live preview

Code

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex">
  <title>Page not found</title>
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-50 text-slate-900">
  <main class="flex min-h-dvh flex-col items-center justify-center px-4 text-center">
    <p class="select-none text-8xl font-black text-indigo-200 sm:text-9xl" aria-hidden="true">404</p>
    <h1 class="mt-2 text-2xl font-bold sm:text-3xl">We could not find that page</h1>
    <p class="mt-2 max-w-md text-slate-600">It may have moved or never existed. Try a search, or pick one of the links below.</p>

    <form action="/search" method="get" role="search" class="mt-8 flex w-full max-w-md gap-2">
      <label for="nf-q" class="sr-only">Search the site</label>
      <input id="nf-q" name="q" type="search" required placeholder="Search..."
        class="min-w-0 flex-1 rounded-lg border border-slate-300 bg-white px-4 py-2.5 focus:outline-2 focus:outline-indigo-600">
      <button type="submit" class="rounded-lg bg-indigo-600 px-5 font-semibold text-white hover:bg-indigo-500">Search</button>
    </form>

    <ul class="mt-8 grid w-full max-w-md grid-cols-2 gap-3 text-sm font-medium">
      <li><a href="/" class="block rounded-lg border border-slate-200 bg-white py-3 hover:border-indigo-300">Home</a></li>
      <li><a href="/pricing" class="block rounded-lg border border-slate-200 bg-white py-3 hover:border-indigo-300">Pricing</a></li>
      <li><a href="/docs" class="block rounded-lg border border-slate-200 bg-white py-3 hover:border-indigo-300">Docs</a></li>
      <li><a href="/contact" class="block rounded-lg border border-slate-200 bg-white py-3 hover:border-indigo-300">Contact</a></li>
    </ul>
  </main>
</body>
</html>

How it works

What it solves

A bare error message strands visitors. A good not-found page admits the miss quickly, offers a way to find what they wanted and lists a few safe destinations. This version needs no scripting at all, which matters because error pages should be the least fragile pages you ship.

How it works

The large "404" is decorative and marked aria-hidden, while the real h1 says the page was not found, so screen readers get a clear heading. The search is a form with role="search", method get and an action pointing at your existing results route; the input name q matches common search endpoints, so the browser performs a normal request and nothing is lost if scripts fail. A labelled input, visible focus ring and a submit button give consistent behaviour. Below it, a short list of popular links uses grid with two columns on small screens. The container uses min-h-dvh so the content centres correctly under mobile browser bars.

Adapting it

Serve it with an HTTP 404 status from your server; the file itself cannot set that. Change the action and parameter name to match your search. Add noindex in the document head so it is not indexed if you also return a 200 by mistake.

Pitfalls

  • A pretty page that returns status 200 creates soft 404s in search consoles.
  • Use root-relative asset paths, because the page can be served at any depth.
  • Keep the link list short; four options are plenty.

How to use it

  1. Save 404.html and configure your server or framework to return it with status 404 for unknown URLs.
  2. Set the form action to your search results route and keep the field name q or change it to match.
  3. Replace the popular links with your own.
  4. Use absolute asset paths (starting with a slash) for any images you add.

Licence: DEV3 Snippet Licence. Free to use, change and ship in personal and commercial projects. Attribution is appreciated, not required. Please do not redistribute snippets as a collection.

Related snippets