<pagefind-searchbox>

An all-in-one search component combining input, results dropdown, and keyboard navigation. Results appear in a floating dropdown below the input and load their full data only when scrolled into view using the Intersection Observer API.

<pagefind-searchbox></pagefind-searchbox>

Attributes

Attribute Type Default Description
placeholder string "Search..." Placeholder text for the input
debounce number 150 Milliseconds to wait after typing
max-results number unlimited Limit number of results shown
show-sub-results boolean false Show anchor-based sub-results in dropdown
show-keyboard-hints boolean true Show keyboard navigation hints in footer
autofocus boolean false Focus input on page load
instance string "default" Connect to a specific Pagefind instance

Keyboard Navigation

Full keyboard support is built in:

Key Action
/ Navigate through results
Enter Go to selected result
Shift+Enter Open result in new tab
Ctrl+Enter / Cmd+Enter Open result in new tab
Escape Close dropdown
Tab Move focus away

Both Shift+Enter and the platform modifier (Ctrl on Windows/Linux, Cmd on Mac) with Enter will open the result in a new tab.

Custom Templates

Like <pagefind-results>, you can customize rendering with <script type="text/pagefind-template"> elements. Templates use a simple syntax with variables, conditionals, and loops.

Basic Template

<pagefind-searchbox>
  <script type="text/pagefind-template">
    <a class="my-result" href="{{ meta.url | default(url) | safeUrl }}">
      <p>{{ meta.title }}</p>
      {{#if excerpt}}
      <p>{{+ excerpt +}}</p>
      {{/if}}
    </a>
  </script>
</pagefind-searchbox>

The full templating syntax can be seen in the adequate-little-templates package.

Available Data

Field Description
meta.title Page title
meta.url Page URL
meta.* Any custom metadata
excerpt Search excerpt with <mark> highlighting (use {{+ excerpt +}})
url Fallback URL
sub_results Array of matching sections (when show-sub-results is set)
options.* The attributes supplied to the <pagefind-searchbox> element
aria.result_id Unique ID for ARIA attributes
aria.title_id ID for the title element
aria.excerpt_id ID for the excerpt element

Each sub-result has: title, url, excerpt, and its own aria object.

Full Template Example

Here’s the built-in template. Copy and customize it:

<pagefind-searchbox>
  <script type="text/pagefind-template">
    <a class="pf-searchbox-result" id="{{ aria.result_id }}" href="{{ meta.url | default(url) | safeUrl }}" role="option" aria-selected="false" aria-labelledby="{{ aria.title_id }}"{{#if excerpt}} aria-describedby="{{ aria.excerpt_id }}"{{/if}}>
      <p class="pf-searchbox-result-title" id="{{ aria.title_id }}">{{ meta.title | default("Untitled") }}</p>
      {{#if excerpt}}
      <p class="pf-searchbox-result-excerpt" id="{{ aria.excerpt_id }}">{{+ excerpt +}}</p>
      {{/if}}
    </a>
    {{#if and(options.show_sub_results, sub_results)}}
    {{#each sub_results as sub}}
    <a class="pf-searchbox-result pf-searchbox-subresult" id="{{ sub.aria.result_id }}" href="{{ sub.url | safeUrl }}" role="option" aria-selected="false" aria-labelledby="{{ sub.aria.title_id }}"{{#if sub.excerpt}} aria-describedby="{{ sub.aria.excerpt_id }}"{{/if}}>
      <p class="pf-searchbox-result-title" id="{{ sub.aria.title_id }}">{{ sub.title | default("Section") }}</p>
      {{#if sub.excerpt}}
      <p class="pf-searchbox-result-excerpt" id="{{ sub.aria.excerpt_id }}">{{+ sub.excerpt +}}</p>
      {{/if}}
    </a>
    {{/each}}
    {{/if}}
  </script>
</pagefind-searchbox>