Skip to content
Corsair UI
Browse the docs

BlocksNo. 133 of 145

Not Found

A 404 page section with a large decorative error code, a page heading, a description, an optional search slot and actions.

Installation

pnpm dlx shadcn@latest add @corsair-ui/not-found

No setup needed: the CLI finds @corsair-ui in the shadcn registry directory. The files land in your project as source: edit them like your own code. More in Installation.

Also adds
utilsbutton
npm
@radix-ui/react-slotclass-variance-authorityclsxlucide-reacttailwind-merge

Examples

Default

The code is decorative; the h1 is the real heading.

Open in a new tab

A small search form in the search slot, above the actions.

Open in a new tab

API

PropTypeDefault
code

The large decorative code above the title; null hides it.

ReactNode"404"
title / description

The title is an h1.

ReactNode"Page not found" / example copy
search

Optional slot between the description and the actions, such as a search form.

ReactNode—
actions

Buttons or links; null hides them.

ReactNode"Go home" and "Contact support"

Styling

Restyle it in your project: className on each part, the theme variables, and these attributes with arbitrary variants, e.g. className="[&_[data-slot=not-found-actions]]:text-primary".

  • The code is not-found-code, large and in the primary colour; the other parts are not-found-title, not-found-description, not-found-search and not-found-actions.
data-slot
  • not-found
  • not-found-actions
  • not-found-code
  • not-found-container
  • not-found-description
  • not-found-search
  • not-found-title

Accessibility

  • The code is hidden with aria-hidden; the h1 is the real heading, so the page is announced by its title.
  • The default actions are links styled as buttons, reachable with Tab.
  • Nothing animates, and it is a server component with no client code.

Compatibility

Tailwind CSS
3.4 and 4, both checked in CI
React
19
Rendering
Works in server components

Source

1 file, installed as source you own
not-found.tsxView on GitHub
import type { ComponentProps, ReactNode } from "react";

import { cn } from "@/registry/default/lib/utils";
import { Button } from "@/registry/default/ui/button";

interface NotFoundProps extends Omit<ComponentProps<"section">, "title"> {
  /** The large error code above the title. It is decorative; pass `null` to hide it. */
  code?: ReactNode;
  /** The page heading, rendered as an `<h1>`. */
  title?: ReactNode;
  description?: ReactNode;
  /** Buttons or links. Defaults to "Go home" and "Contact support"; pass `null` to hide them. */
  actions?: ReactNode;
  /** Optional slot between the description and the actions, such as a search form. */
  search?: ReactNode;
}

const defaultActions = (
  <>
    <Button asChild size="lg">
      <a href="/">Go home</a>
    </Button>
    <Button asChild size="lg" variant="outline">
      <a href="#contact">Contact support</a>
    </Button>
  </>
);

/**
 * A "page not found" section: a large error code, the page title, a short
 * description, an optional `search` slot and actions, centred.
 * `<NotFound />` renders a complete 404 example.
 *
 * Accessibility: the code ("404") is decorative and hidden from screen
 * readers with `aria-hidden`; the real heading is the `title` `<h1>`
 * ("Page not found"), so assistive tech hears a meaningful page title.
 * The default actions are links styled as buttons, reachable with Tab.
 * Nothing animates. It is a server component: no client code.
 *
 * @example
 * <NotFound
 *   code="410"
 *   title="This page is gone"
 *   description="The project was archived."
 *   actions={
 *     <Button asChild>
 *       <a href="/projects">All projects</a>
 *     </Button>
 *   }
 * />
 */
function NotFound({
  code = "404",
  title = "Page not found",
  description = "Sorry, we couldn't find the page you're looking for. It may have been moved or deleted.",
  actions = defaultActions,
  search,
  className,
  ...props
}: NotFoundProps) {
  return (
    <section data-slot="not-found" className={cn("py-16 sm:py-24", className)} {...props}>
      <div
        data-slot="not-found-container"
        className="mx-auto flex w-full max-w-6xl flex-col items-center px-4 text-center sm:px-6"
      >
        {code != null ? (
          <p
            aria-hidden="true"
            data-slot="not-found-code"
            className="text-primary text-7xl leading-none font-bold tracking-tight sm:text-9xl"
          >
            {code}
          </p>
        ) : null}
        <h1
          data-slot="not-found-title"
          className={cn(
            "max-w-2xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl",
            code != null && "mt-6"
          )}
        >
          {title}
        </h1>
        {description ? (
          <p
            data-slot="not-found-description"
            className="text-muted-foreground mt-4 max-w-xl text-lg text-pretty"
          >
            {description}
          </p>
        ) : null}
        {search ? (
          <div data-slot="not-found-search" className="mt-8 w-full max-w-md">
            {search}
          </div>
        ) : null}
        {actions ? (
          <div
            data-slot="not-found-actions"
            className="mt-10 flex flex-wrap items-center justify-center gap-3"
          >
            {actions}
          </div>
        ) : null}
      </div>
    </section>
  );
}

export { NotFound, type NotFoundProps };