Search Led 404

(Missing)

Tell us what you came for and we will find it.

The address you used does not resolve to anything. Search the site instead, or take one of the routes people use most.

Search covers every project, note and page we publish.

About this block

Search Led 404PRO

Monochrome 404 that hands the visitor a search field: a display headline with a muted emphasis clause, a rounded search bar with a circular submit seal wired to a callback, and a ruled list of the most travelled routes.

Error30: Search Led 404

A monochrome 404 that hands the visitor a search field instead of an apology: a rounded search bar with a circular submit seal sits under the headline, followed by a ruled list of the routes people actually take.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/error30?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/error30?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/error30.tsx, plus the badge7 design-system primitive it renders the parenthetical eyebrows through.

Quick start

The installed file exports error30Demo alongside the block: the exact props behind the preview above. Spread it to get a working search page in one line.

tsx
import { Error30, error30Demo } from "@/components/beste/block/error30";

export default function NotFound() {
  return <Error30 {...error30Demo} />;
}

Routing is the caller's job, so wire onSearch to your search page:

tsx
"use client";

import { useRouter } from "next/navigation";
import { Error30 } from "@/components/beste/block/error30";

export default function NotFound() {
  const router = useRouter();

  return (
    <Error30
      badge={{ label: "Missing" }}
      heading="Tell us what you came for <strong>and we will find it</strong>."
      description="The address you used does not resolve to anything."
      labels={{
        placeholder: "Search the site",
        suggestionsTitle: "Most travelled",
        note: "Search covers every project, note and page we publish.",
      }}
      suggestions={[
        { title: "Recent projects", description: "The last twelve months of work", href: "/work" },
        { title: "How we price", description: "Bands, retainers and what changes them", href: "/pricing" },
      ]}
      onSearch={(query) => router.push(`/search?q=${encodeURIComponent(query)}`)}
    />
  );
}

Props

PropTypeDefaultDescription
badge{ label: string }–Parenthetical eyebrow above the headline
headingstring–Headline HTML, rendered as an h1; <strong> marks the muted clause
descriptionstring–Explanatory paragraph under the headline
labelsError30Labels{}Field placeholder, list eyebrow, and the note under the field
suggestionsSuggestionItem[][]Ruled rows of suggested routes
onSearch(query: string) => void–Called on submit with the trimmed query
classNamestring–Extra classes for the outer <section>
ts
type Error30Labels = {
  placeholder?: string;
  suggestionsTitle?: string;
  note?: string;
};

type SuggestionItem = {
  title: string;
  description?: string;
  href: string;
};

Behavior notes

  • The search field is a controlled React input inside a real form. Submitting prevents the default action and passes the trimmed query to onSearch, so nothing navigates by default and the preview above stays put.
  • Without an onSearch handler the form still submits harmlessly, which keeps the block safe to drop in before search exists.
  • The input is type="search", so browsers render their native clear affordance, and the placeholder doubles as its aria-label. The circular submit control carries its own written label for screen readers.
  • Suggestion rows are separated by top borders rather than a bordered list container, and hover only shifts the trailing arrow from muted to full contrast through the named group/error30 group.
  • heading is injected with dangerouslySetInnerHTML and accepts inline HTML; text inside <strong> drops to muted grey. Keep the value under your own control, never user input.

More Error blocks

View all Error
PRO

error19

Typographic 404 Index

FREE

error2

404 With Site Search

PRO

error32

404 With Recent Writing

Get Pro access