Skip to main content
The SearchBox component provides a styled search input with a submit button, automatic language detection, keyboard shortcuts, and analytics tracking.

Import

import SearchBox from "../components/SearchBox.astro";

Usage

Basic Usage

src/pages/[lang]/index.astro
---
import SearchBox from "../../components/SearchBox.astro";
---

<SearchBox />

With Custom Placeholder

<SearchBox placeholder="Buscar palabra..." />

With Pre-filled Query

src/pages/[lang]/buscar.astro
---
const urlParams = new URLSearchParams(Astro.url.search);
const query = urlParams.get("q") || "";
---

<SearchBox 
  placeholder={t("home.search.placeholder")} 
  query={query}
/>

Props

placeholder
string
default:"Buscar palabra..."
The placeholder text displayed in the search input field. Should be localized based on the current language.
query
string
default:""
Pre-fill the search input with an initial query value. Useful for displaying search results pages with the current search term.

Features

Language Detection

The component automatically detects the current language and sets the appropriate search action URL:
const lang = getLangFromUrl(Astro.url);
const prefix = lang === "en" ? "/en" : "/es";
const action = `${prefix}/buscar/`;

Form Structure

<form
  class="bg-card border-theme shadow-theme-sm flex items-center gap-2 rounded-lg border p-1"
  action={action}
  method="get"
>
  <input
    type="search"
    name="q"
    value={query}
    placeholder={placeholder}
    aria-label={t("search.aria_label")}
    class="text-theme min-w-0 flex-1 border-none bg-transparent"
  />
  <button
    class="search-btn"
    type="submit"
    aria-label={t("search.button_aria_label")}
  >
    <Search size={16} />
    <span class="hidden md:inline">{t("search.button_text")}</span>
  </button>
</form>

Keyboard Shortcuts

Press / to focus the search input from anywhere on the page:
document.addEventListener("keydown", (e) => {
  if (e.key === "/" && !(e.target instanceof HTMLInputElement)) {
    e.preventDefault();
    const input = document.querySelector('input[type="search"]');
    input?.focus();
  }
});
The keyboard shortcut only works when focus is not already on an input element to avoid interfering with typing.

Analytics Tracking

Search submissions are automatically tracked with Umami:
document.addEventListener("astro:page-load", () => {
  const form = document.querySelector('form[action*="buscar"]');
  if (form) {
    form.addEventListener("submit", () => {
      const input = form.querySelector('input[name="q"]');
      if (input && input.value && window.umami) {
        window.umami.track("Search", { query: input.value });
      }
    });
  }
});

Styling

Search Button

The submit button has gradient styling and dynamic effects:
.search-btn {
  position: relative;
  background: var(--btn-primary-bg);
  box-shadow:
    0 2px 8px var(--btn-primary-shadow),
    0 1px 3px var(--shadow-md);
}

.search-btn:hover {
  box-shadow:
    0 4px 12px var(--btn-primary-shadow),
    0 2px 6px var(--shadow-md);
  transform: translateY(-1px);
}

.search-btn:active {
  box-shadow: 0 1px 4px var(--btn-primary-shadow);
  transform: translateY(0) scale(0.95);
}

Responsive Behavior

The button text is hidden on mobile devices:
<span class="hidden md:inline">
  {t("search.button_text")}
</span>

Accessibility

ARIA Labels

Both the input and button include proper ARIA labels:
<input
  aria-label={t("search.aria_label")}
  type="search"
/>

<button
  aria-label={t("search.button_aria_label")}
  type="submit"
>

Focus States

Visible focus indicators for keyboard navigation:
.search-btn:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

Internationalization

The component uses the useTranslations() helper for all text:
const t = useTranslations(lang);

<input aria-label={t("search.aria_label")} />
<button aria-label={t("search.button_aria_label")}>
  <span>{t("search.button_text")}</span>
</button>

Translation Keys

  • search.aria_label - Input field label
  • search.button_aria_label - Button label
  • search.button_text - Button visible text

Form Submission

The form submits to /{lang}/buscar/ with the query parameter:
GET /es/buscar/?q=chapín
GET /en/buscar/?q=guatemalan

View Transitions

The component works seamlessly with Astro’s View Transitions API. The search state persists across navigation, and event listeners are reattached on page load:
document.addEventListener("astro:page-load", () => {
  // Reattach event listeners
});

Layout Examples

Hero Section

<section class="hero">
  <h1>Diccionario Chapín</h1>
  <p>Discover Guatemalan slang</p>
  <SearchBox placeholder="Search for a word..." />
</section>

Search Page

<div class="mx-auto max-w-[1100px] px-6">
  <div class="card-with-gradient shadow-theme-lg my-6">
    <h1 class="gradient-text">{t("search.title")}</h1>
    <p class="text-muted">{t("search.subtitle")}</p>
    <SearchBox placeholder={t("home.search.placeholder")} />
  </div>
  <div id="searchResults"></div>
</div>

Browser Support

  • Modern browsers with ES6+ support
  • input[type="search"] for native search functionality
  • CSS custom properties for theming
  • View Transitions API (with fallback)

Build docs developers (and LLMs) love