# Not found 2

> Split layout — oversized mono 404 left, registry copy and dual CTAs right.

A shadcn/ui block from the [@nusaiba](https://nusaiba.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/nusaiba/not-found-2).

- Page, with a live preview: https://shadcn.exchange/r/nusaiba/not-found-2
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/nusaiba/not-found-2-light-ce067d4ab123f92b.png
- Registry item: https://nusaiba.dev/r/base-nova/not-found-2.json
- Categories: not-found
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://nusaiba.dev/r/base-nova/not-found-2.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `motion`
- Registry items: `@nusaiba/foundation`, `button`

## Files

### `registry/blocks/not-found/not-found-data.ts`

```ts
export const notFoundCode = "404";

export const notFoundHome = {
	label: "Back to home",
	href: "/",
} as const;

export const notFoundCenteredCopy = {
	title: "Page not found",
	description:
		"The page you're looking for doesn't exist or has been moved. Check the URL or head back home.",
} as const;

export const notFoundSplitCopy = {
	title: "This route isn't in the registry",
	description:
		"The path may have been renamed after a block update — browse the catalog or open docs for install paths.",
} as const;

export const notFoundFramedCopy = {
	eyebrow: "Missing page",
	title: "Nothing installed here",
	description: "Return to the registry home or search the block catalog for what you need.",
} as const;

export const notFoundSearchCopy = {
	title: "Can't find that page",
	description: "Search the block catalog or jump to a common destination below.",
	placeholder: "Search blocks…",
} as const;

export const notFoundCycleCopy = {
	title: "Wrong status code",
	description: "You landed on a route that doesn't resolve — pick a path below to keep shipping.",
} as const;

export const notFoundGridCopy = {
	title: "Try one of these instead",
	description: "Common destinations when a deep link goes stale after a registry update.",
} as const;

export const notFoundPathCopy = {
	title: "Route not found",
	description: "The URL below didn't match any page in this preview — update the path or go back.",
	brokenPath: "/blocks/registry/unknown-block",
} as const;

export const notFoundVisualCopy = {
	title: "Lost in the grid",
	description: "The section you wanted isn't here — head home or browse blocks to keep moving.",
} as const;

export const notFoundStackCopy = {
	eyebrow: "404",
	title: "Where to next",
	description: "Pick a destination — each link opens a live registry surface.",
} as const;

export const notFoundTerminalCopy = {
	eyebrow: "stderr",
	title: "ENOENT: page not found",
	description: "Exit code 404 — rerun from home or list available routes.",
} as const;

export type NotFoundLink = {
	label: string;
	href: string;
	description?: string;
};

export const notFoundQuickLinks: NotFoundLink[] = [
	{
		label: "Browse blocks",
		href: "/blocks",
		description: "Preview every section before you install",
	},
	{
		label: "Read docs",
		href: "/docs",
		description: "CLI install paths and Copy Prompt handoff",
	},
	{
		label: "Pricing",
		href: "/pricing",
		description: "Free vs Pro blocks and licensing",
	},
	{
		label: "Motion",
		href: "/motion",
		description: "Animation patterns tied to live blocks",
	},
];

export const notFoundStatusCodes = ["401", "403", "404", "410"] as const;
```

### `registry/blocks/not-found/not-found-primitives.tsx`

```tsx
"use client";

import Link from "next/link";
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
import { motion, useInView, useReducedMotion } from "motion/react";
import { useRef, type ReactNode } from "react";
import { buttonVariants } from "@/components/ui/button";
import { SectionShell } from "@/components/layout-contract";
import { motionStagger, motionViewport } from "@/lib/motion-tokens";
import { cn } from "@/lib/utils";
import { notFoundCode, notFoundHome, type NotFoundLink } from "./not-found-data";

const spring = { type: "spring" as const, duration: 0.3, bounce: 0 };

export function useNotFoundItemVariants() {
	const reduceMotion = useReducedMotion();

	return reduceMotion
		? { hidden: { opacity: 1 }, visible: { opacity: 1 } }
		: {
				hidden: { opacity: 0, filter: "blur(4px)", y: 8 },
				visible: { opacity: 1, filter: "blur(0px)", y: 0, transition: spring },
			};
}

export function NotFoundStagger({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	const ref = useRef<HTMLDivElement>(null);
	const inView = useInView(ref, motionViewport);

	return (
		<motion.div
			animate={inView ? "visible" : "hidden"}
			className={className}
			initial="hidden"
			ref={ref}
			variants={{
				hidden: {},
				visible: { transition: { staggerChildren: motionStagger.item, delayChildren: 0.04 } },
			}}
		>
			{children}
		</motion.div>
	);
}

export function NotFoundStaggerItem({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	const itemVariants = useNotFoundItemVariants();

	return (
		<motion.div className={className} variants={itemVariants}>
			{children}
		</motion.div>
	);
}

export function NotFoundCode({
	className,
	size = "lg",
}: {
	className?: string;
	size?: "lg" | "xl";
}) {
	return (
		<p
			className={cn(
				"font-mono font-medium tracking-tighter tabular-nums",
				size === "xl" ? "text-7xl md:text-8xl" : "text-6xl md:text-7xl",
				className,
			)}
		>
			{notFoundCode}
		</p>
	);
}

export function NotFoundHomeLink({ className }: { className?: string }) {
	return (
		<Link className={cn(buttonVariants(), "active:scale-[0.96] transition-transform", className)} href={notFoundHome.href}>
			<ArrowLeftIcon data-icon="inline-start" />
			{notFoundHome.label}
		</Link>
	);
}

export function NotFoundOutlineLink({
	href,
	children,
	className,
}: {
	href: string;
	children: ReactNode;
	className?: string;
}) {
	return (
		<Link
			className={cn(
				buttonVariants({ variant: "outline", size: "sm" }),
				"active:scale-[0.96] transition-transform",
				className,
			)}
			href={href}
		>
			{children}
		</Link>
	);
}

export function NotFoundLinkCard({ link }: { link: NotFoundLink }) {
	return (
		<Link
			className="group flex flex-col gap-1 rounded-xl border border-border bg-background p-4 transition-colors hover:bg-muted/30 active:scale-[0.98]"
			href={link.href}
		>
			<span className="flex items-center justify-between gap-2 font-medium text-sm">
				{link.label}
				<ArrowRightIcon className="size-3.5 text-muted-foreground transition-transform group-hover:translate-x-0.5" />
			</span>
			{link.description ? (
				<span className="text-pretty text-muted-foreground text-xs leading-relaxed">
					{link.description}
				</span>
			) : null}
		</Link>
	);
}

export function NotFoundLinkRow({ link }: { link: NotFoundLink }) {
	return (
		<Link
			className="group flex min-h-11 items-center justify-between gap-4 border-border border-b py-3.5 last:border-b-0 transition-colors hover:bg-muted/25"
			href={link.href}
		>
			<div className="min-w-0">
				<p className="font-medium text-sm">{link.label}</p>
				{link.description ? (
					<p className="mt-0.5 truncate text-muted-foreground text-xs">{link.description}</p>
				) : null}
			</div>
			<ArrowRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-hover:translate-x-0.5" />
		</Link>
	);
}

export function NotFoundSectionShell({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	return (
		<SectionShell spacingMode="section" className={cn("flex min-h-[70vh] items-center", className)}>
			{children}
		</SectionShell>
	);
}
```

### `registry/blocks/not-found/2/not-found-section.tsx`

```tsx
"use client";

import { notFoundQuickLinks, notFoundSplitCopy } from "../not-found-data";
import {
	NotFoundCode,
	NotFoundHomeLink,
	NotFoundOutlineLink,
	NotFoundSectionShell,
	NotFoundStagger,
	NotFoundStaggerItem,
} from "../not-found-primitives";

export function NotFoundSplitSection() {
	return (
		<NotFoundSectionShell>
			<div className="mx-auto grid w-full max-w-4xl items-center gap-10 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:gap-14">
				<NotFoundStagger className="text-center lg:text-left">
					<NotFoundStaggerItem>
						<NotFoundCode size="xl" />
					</NotFoundStaggerItem>
				</NotFoundStagger>

				<NotFoundStagger>
					<NotFoundStaggerItem>
						<h1 className="text-balance font-medium text-2xl tracking-tight md:text-3xl">
							{notFoundSplitCopy.title}
						</h1>
					</NotFoundStaggerItem>
					<NotFoundStaggerItem>
						<p className="mt-4 text-pretty text-muted-foreground text-sm leading-relaxed md:text-base">
							{notFoundSplitCopy.description}
						</p>
					</NotFoundStaggerItem>
					<NotFoundStaggerItem>
						<div className="mt-8 flex flex-wrap gap-3">
							<NotFoundHomeLink />
							<NotFoundOutlineLink href={notFoundQuickLinks[0]!.href}>
								{notFoundQuickLinks[0]!.label}
							</NotFoundOutlineLink>
						</div>
					</NotFoundStaggerItem>
				</NotFoundStagger>
			</div>
		</NotFoundSectionShell>
	);
}
```
