# Not Found

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

Docs: https://corsairui.vercel.app/docs/not-found

## Install

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

Also adds: `utils`, `button`.
npm: `@radix-ui/react-slot`, `class-variance-authority`, `clsx`, `lucide-react`, `tailwind-merge`.

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `code` | `ReactNode` | `"404"` | The large decorative code above the title; null hides it. |
| `title / description` | `ReactNode` | `"Page not found" / example copy` | The title is an h1. |
| `search` | `ReactNode` |  | Optional slot between the description and the actions, such as a search form. |
| `actions` | `ReactNode` | `"Go home" and "Contact support"` | Buttons or links; null hides them. |

## Styling

Restyle it in the project that installs it: `className` on each part, the theme variables, and these attributes with arbitrary variants (`[&_[data-slot=…]]:…`, `data-[state=…]:…`).

- 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.

## Examples

On the docs page: Default, With search. The usage examples in the source comments below are the reference.

## Source

What `shadcn add` writes into the project:

### not-found.tsx

```tsx
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 };
```
