# Search bar (themes.dev UI block)

A short heading and one line in a centred panel, then the search field with its clear button and / shortcut. Black and white, dark mode, shadcn-compatible; React, Astro and plain HTML.

9.6% of the 2,073 sites in The UI Index have a search (200 sites).

## Install

- React: `npx shadcn@latest add https://www.themes.dev/ui/r/search-bar.json`
- Astro: `npx shadcn@latest add https://www.themes.dev/ui/r/astro/search-bar.json`
- HTML: https://www.themes.dev/ui/r/html/search-bar.html (with https://www.themes.dev/ui/r/html/caseroom.css)

Page: https://www.themes.dev/ui/blocks/search-bar/ · Rules for agents: https://www.themes.dev/ui/AGENT.md

## Code

### search-bar.astro

```astro
---
import SearchField from '@/components/ui/search-field.astro';
import { cn } from '@/lib/utils';
import { searchBar as c, type SearchBarContent } from './search-bar.classes';

type Props = SearchBarContent & { class?: string };
const { heading, lead, label, placeholder, action, name, value, id, class: className } = Astro.props;
---

<section aria-labelledby={`${id}-title`} class={cn(c.root, className)}>
  <div class={c.frame}>
    <div class={c.head}>
      <h2 id={`${id}-title`} class={c.heading}>{heading}</h2>
      {lead && <p class={c.lead}>{lead}</p>}
    </div>
    <SearchField id={`${id}-q`} label={label} placeholder={placeholder} action={action} name={name} value={value} />
  </div>
</section>
```

### search-bar.classes.ts

```tsx
/** A search bar (ported from the themes' sections/search): a short heading and one line in a centred panel, then
 *  the search field (the free search-field: magnifier, a native search input, a "/" shortcut, a clear button once
 *  there is text). A GET form that works without JavaScript. */
export const searchBar = {
  root: 'bg-background px-6 py-16 text-foreground',
  frame: 'mx-auto flex w-full max-w-3xl min-w-0 flex-col gap-6 rounded-xl border bg-card p-5 text-card-foreground sm:p-8',
  head: 'flex flex-col gap-2',
  heading: 'text-xl font-semibold tracking-[-0.02em] text-balance',
  lead: 'text-base text-pretty text-muted-foreground',
};

export type SearchBarContent = {
  /** The panel's short heading. */
  heading: string;
  lead?: string;
  /** The field's accessible name, e.g. "Search the docs". */
  label: string;
  placeholder?: string;
  /** Where the search form goes (GET); it works without JavaScript. */
  action: string;
  /** The query's name. Default: q. */
  name?: string;
  /** The text already in the field. */
  value?: string;
  /** Unique on the page; ids the heading and the field. */
  id: string;
};
```

### search-bar.tsx

```tsx
import { SearchField } from '@/components/ui/search-field';
import { cn } from '@/lib/utils';
import { searchBar as c, type SearchBarContent } from './search-bar.classes';

export type SearchBarProps = SearchBarContent & { className?: string };

/** A search bar: a short heading and one line in a panel, then the search field. */
export function SearchBar({ heading, lead, label, placeholder, action, name, value, id, className }: SearchBarProps) {
  return (
    <section aria-labelledby={`${id}-title`} className={cn(c.root, className)}>
      <div className={c.frame}>
        <div className={c.head}>
          <h2 id={`${id}-title`} className={c.heading}>{heading}</h2>
          {lead && <p className={c.lead}>{lead}</p>}
        </div>
        <SearchField id={`${id}-q`} label={label} placeholder={placeholder} action={action} name={name} defaultValue={value} />
      </div>
    </section>
  );
}
```
