Search Hero

A pine-backed cove crowded with swimmers

A library of finished screens

Alreadybuilt.

Every section a website needs, written once and kept calm. Search for the one you are missing.

About this block

Search HeroPRO

A centred photographic hero built around a search field: the photograph blurs in and drifts slower than the page under a dark scrim and film grain, a serif headline settles in word by word, then a rounded search field with a keyboard shortcut hint, a row of quick links and optional pills. The field can hand its click to a command palette instead of being a form.

Hero187: Search Hero

A photographic hero built around a search field: the picture clears from a blur and drifts under a dark scrim and film grain, the headline settles in word by word, and a rounded field with a keyboard hint sits under it above a row of quick links.

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/hero187?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

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

This installs the block to components/beste/block/hero187.tsx, the shadcn input primitive the field is built on, and the button22 sliding-marker pill and the text1 word stagger it uses.

Quick start

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

tsx
import { Hero187, hero187Demo } from "@/components/beste/block/hero187";

export default function Page() {
  return <Hero187 {...hero187Demo} />;
}

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsx
import { Hero187 } from "@/components/beste/block/hero187";

export default function Page() {
  return (
    <Hero187
      eyebrow="A library of finished screens"
      heading="Already built."
      description="Every section a website needs, written once and kept calm."
      image={{ src: "/photos/hills.jpg", alt: "Soft fog rolling over layered green hills" }}
      search={{
        placeholder: "Search blocks, pieces and components",
        label: "Search",
        shortcut: ["⌘", "K"],
      }}
      onSearch={() => console.log("open the command palette")}
      suggestionsLabel="Often opened"
      suggestions={[
        { label: "Heroes", href: "/blocks/hero" },
        { label: "Pricing", href: "/blocks/pricing" },
      ]}
    />
  );
}

Props

PropTypeDefaultDescription
eyebrowstring–Small-caps line above the headline
headingstring–Headline, rendered as the page h1 through Text1
descriptionstring–Paragraph under the headline
image{ src: string; alt: string }–Full-bleed background photograph
searchSearch–The field's placeholder, accessible name and keyboard hint
onSearch() => void–When given, the field becomes a button that calls this instead of a form
suggestionsSuggestion[][]Quick links under the field
suggestionsLabelstring–Small-caps label before the quick links
buttonsActionButton[][]Pill actions under the links; each defaults to the light tone
classNamestring–Extra classes for the outer <section>
ts
type Search = {
  placeholder: string;
  label: string;
  shortcut?: string[];
};

type Suggestion = {
  label: string;
  href: string;
};

type ActionButton = {
  label: string;
  href: string;
  tone?: "primary" | "light" | "dark" | "outline";
};

Behavior notes

  • onSearch changes what the field actually is. Without it you get a real form with an input; with it you get a button wearing the same shape, which is the right markup when the search lives in a command palette or on another page and this is only the thing you press to reach it.
  • In the form variant the label is sr-only and tied to the input through a useId, so the field is named for a screen reader without a visible label crowding the pill; in the button variant that name comes from aria-label instead.
  • shortcut is a plain array of strings, so ["⌘", "K"] and ["Ctrl", "K"] both render as key caps. It is aria-hidden and hidden below sm, since a keyboard hint is noise on a phone and on a screen reader.
  • The field is drawn on bg-background inside a dark hero, so it is the one light object on the screen; the shadcn Input is stripped of its border, shadow and focus ring so the pill around it reads as the control.
  • The section is min-h-[40rem] rising to min-h-[46rem] rather than min-h-svh: a search hero wants to leave the first results or section visible under it rather than filling the viewport.
  • The headline runs with trigger="mount", since a hero is above the fold, and everything under it is offset from 0.4 + heading.split(" ").length * 0.07 so the field, the links and the buttons arrive in that order.
  • The photograph clears from a 1.12 scale and blur(24px) on decode, with a complete check on mount because a cached image fires its load event before hydration, and drifts 26% as the page scrolls away.
  • The form variant only calls preventDefault() on submit, so nothing is searched until you wire it up or hand the click to onSearch.

Wiring the form up

This block ships the form markup only; state, validation, and submit are yours to add. Our guide wires the shadcn Field primitives to React Hook Form, TanStack Form, and Formisch on one field system.

More Hero blocks

View all Hero
PRO

hero182

Centred Photo Hero

PRO

hero171

Search-First Archive Hero

PRO

hero176

Unveiling Hero

Get Pro access