# Empty Search No Results — React Empty State

> A no-results state with a scanning magnifier, a working search field and suggestion chips that stagger in and fill the query when clicked.

- Category: [Empty States](https://pixelpapa.com/components/empty-states.md)
- Tags: empty-state, search, suggestions, chips, no-results
- Dependencies: lucide-react, motion (plus React and Tailwind CSS v4)
- Last updated: 2026-11-13
- Live preview: https://pixelpapa.com/components/empty-states/empty-search-no-results

## Install

```bash
npx shadcn@latest add "https://pixelpapa.com/r/empty-search-no-results.json"
```

The file is written to `components/pixelpapa/empty-search-no-results.tsx`. To install manually, run `npm install lucide-react motion` and copy the source below into your project. It imports `cn` from `@/lib/utils`, which every shadcn project has.

## Source

```tsx
"use client";

import { CornerDownLeft, Search, X } from "lucide-react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { useState } from "react";

type EmptySearchNoResultsProps = {
  defaultQuery?: string;
  suggestions?: string[];
};

const known = ["quarterly report", "invoice template", "brand guidelines", "onboarding deck"];

export default function EmptySearchNoResults({ defaultQuery = "quaterly repot", suggestions = known }: EmptySearchNoResultsProps) {
  const [query, setQuery] = useState(defaultQuery);
  const reduce = useReducedMotion();
  const found = suggestions.includes(query.trim().toLowerCase());

  return (
    <div className="w-full max-w-md">
      <div className="flex h-12 items-center gap-3 rounded-2xl border border-input bg-card px-4 transition-shadow focus-within:border-primary focus-within:ring-4 focus-within:ring-primary/15">
        <Search className="size-4 text-muted-foreground" />
        <label htmlFor="empty-search-no-results-input" className="sr-only">
          Search files
        </label>
        <input
          id="empty-search-no-results-input"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search files"
          className="min-w-0 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
        />
        {query && (
          <button type="button" onClick={() => setQuery("")} aria-label="Clear search" className="flex size-6 items-center justify-center rounded-full text-muted-foreground hover:bg-muted hover:text-foreground">
            <X className="size-3.5" />
          </button>
        )}
      </div>

      <div className="mt-3 rounded-3xl border border-border bg-card px-8 py-9 text-center">
        <AnimatePresence mode="wait" initial={false}>
          {found ? (
            <motion.div key="found" initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }}>
              <p className="text-sm text-muted-foreground">1 result</p>
              <p className="mt-3 flex items-center justify-between rounded-xl bg-muted px-4 py-3 text-left text-sm font-medium text-foreground capitalize">
                {query}.pdf <CornerDownLeft className="size-4 text-muted-foreground" />
              </p>
            </motion.div>
          ) : (
            <motion.div key="empty" initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }}>
              <div className="relative mx-auto h-20 w-36" aria-hidden>
                {[0, 1, 2].map((i) => (
                  <span key={i} className="absolute left-4 h-2.5 rounded-full bg-muted" style={{ top: 14 + i * 20, width: 112 - i * 22 }} />
                ))}
                <motion.span
                  className="absolute top-0 left-0 flex size-14 items-center justify-center rounded-full border-2 border-primary bg-primary/10 backdrop-blur-[2px]"
                  animate={reduce ? undefined : { x: [8, 78, 40, 8], y: [4, 10, 24, 4], rotate: [0, 8, -6, 0] }}
                  transition={{ duration: 4.5, repeat: Infinity, ease: "easeInOut" }}
                  initial={{ x: 40, y: 12 }}
                >
                  <span className="absolute -right-3 -bottom-3 h-5 w-1 origin-top -rotate-45 rounded-full bg-primary" />
                  <span className="text-lg font-semibold text-primary">?</span>
                </motion.span>
              </div>
              <h3 className="mt-5 text-lg font-semibold tracking-tight text-card-foreground">
                {query ? <>Nothing matches “{query}”</> : "Type to search 1,284 files"}
              </h3>
              <p className="mt-1.5 text-sm text-muted-foreground">Check the spelling, or try one of these.</p>
              <motion.ul
                initial="hidden"
                animate="shown"
                transition={{ staggerChildren: 0.06, delayChildren: 0.15 }}
                className="mt-5 flex flex-wrap justify-center gap-2"
              >
                {suggestions.map((s) => (
                  <motion.li key={s} variants={{ hidden: { opacity: 0, y: 8, scale: 0.9 }, shown: { opacity: 1, y: 0, scale: 1 } }}>
                    <motion.button
                      type="button"
                      whileHover={{ y: -2 }}
                      whileTap={{ scale: 0.95 }}
                      onClick={() => setQuery(s)}
                      className="rounded-full border border-border bg-background px-3 py-1.5 text-sm text-foreground transition-colors hover:border-primary hover:text-primary"
                    >
                      {s}
                    </motion.button>
                  </motion.li>
                ))}
              </motion.ul>
            </motion.div>
          )}
        </AnimatePresence>
      </div>
    </div>
  );
}
```

## AI prompt

```text
Add the "Empty Search No Results" component from PixelPapa UI to this project.

What it is: A no-results state with a scanning magnifier, a working search field and suggestion chips that stagger in and fill the query when clicked.
Category: Empty States. Depends on: lucide-react, motion.

1. Install it with the shadcn CLI:
   npx shadcn@latest add "https://pixelpapa.com/r/empty-search-no-results.json"
   (If the CLI is unavailable, fetch that URL, write files[0].content to components/pixelpapa/empty-search-no-results.tsx and install the listed dependencies.)
2. Import it from "@/components/pixelpapa/empty-search-no-results" and place it where I describe below.
3. Keep its animation timings and accessibility attributes. Replace the demo copy and data with content that fits my product, and use my existing theme tokens (bg-background, text-foreground, bg-primary, border-border) rather than hard-coded colours.

Where to use it: <describe the page and position here>
```

## More empty states

- [Empty Error Retry](https://pixelpapa.com/components/empty-states/empty-error-retry.md) (Pro): A failed-to-load state with a flickering unplugged-cable drawing and a retry button that spins, fails once with a shake, then reconnects with a spark.
- [Empty First Project](https://pixelpapa.com/components/empty-states/empty-first-project.md): A first-run dropzone whose dashed border marches, tightens and tints while a file is dragged over it, with a primary action and starter templates.
- [Empty Inbox Illustration](https://pixelpapa.com/components/empty-states/empty-inbox-illustration.md): An inbox-zero state with an animated SVG tray: a paper plane loops overhead on a dashed trail while the tray bobs and sparkles blink.
