File: README.md
Pagefind
Pagefind is a fully static search library that aims to perform well on large sites, while using as little of your usersβ bandwidth as possible, and without hosting any infrastructure.
The full documentation on using Pagefind can be found at https://pagefind.app/.
File: docs/content/docs/components/_index.md
title: "Component System" nav_title: "Component System" weight: 2
The Pagefind Component UI is a set of web components that communicate through shared instances. This allows you to compose search interfaces from individual pieces, or use the prebuilt components that bundle everything together.
How Components Connect
Components on the same page automatically connect to each other. In this example, pagefind-input triggers searches, pagefind-summary shows the count, and pagefind-results displays the matches.
Named Instances
Use the instance attribute to create separate, independent search interfaces on the same page:
Components with the same instance value share state. Components with different instance values are completely independent β they maintain separate search terms, filters, and results.
Component Categories
Full Experiences
These components provide complete, ready-to-use search interfaces:
- Modal β A dialog search with keyboard navigation. Supports custom inner structure
- Modal Trigger β A button that opens the modal
- Searchbox β A compact dropdown search
Building Blocks
These components can be composed together for custom layouts:
- Input β The search text field
- Results β The list of search results
- Summary β Shows result count and search status
- Keyboard Hints β Shows contextual keyboard shortcuts
- Filter Dropdown β A dropdown to filter by a specific facet
- Filter Pane β A sidebar-style filter panel with checkboxes
Configuration
- Config β Set options for the Component UI, or for Pagefind itself
File: docs/content/docs/components/config.md
title: "" nav_title: "" nav_section: Components weight: 100
Declaratively configure a Pagefind instance. Optionally include this on the page to set options like bundle path.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
bundle-path |
string | auto-detected | Path to Pagefind bundle files |
base-url |
string | "/" |
Base URL prepended to all result links |
excerpt-length |
number | 30 |
Length of result excerpts (in words) |
lang |
string | auto-detected | Override the detected language for stemming and translations |
instance |
string | "default" |
Instance name to configure |
preload |
boolean | false |
Load Pagefind immediately instead of on first search |
faceted |
boolean | false |
Enable faceted search mode |
highlight-param |
string | β | Add the search term as a query parameter under this key for use with the highlight script |
exact-diacritics |
boolean | false |
Treat diacritics as distinct characters instead of normalizing them |
meta-cache-tag |
string | β | Replace the default cache-busting timestamp with a fixed string for offline/PWA support |
no-worker |
boolean | false |
Force Pagefind to run on the main thread instead of a web worker |
Bundle Path Detection
By default, bundle-path is automatically detected from the location of the Pagefind script. If the script is loaded from /assets/pagefind/pagefind-component-ui.js, the bundle path defaults to /assets/pagefind/. If detection fails, it falls back to /pagefind/.
Important: Attributes Are Read Once
Attributes are only read when the component connects to the DOM. Changing attributes dynamically after connection has no effect. For dynamic configuration, use the JavaScript API instead.
Examples
Custom Bundle Path
When your Pagefind files are in a non-standard location:
External Bundle
Load from another domain:
Preload
Load Pagefind immediately on page load (instead of waiting for first search):
This improves perceived performance for search-only pages but adds initial page weight.
Faceted Search Mode
Enable faceted/browse mode for catalog-style interfaces where users filter content without requiring a search term:
When faceted is enabled:
- Searching with an empty term returns all results (instead of showing nothing)
- Results update immediately when filters are changed
Combine with preload to show all results immediately on page load. Without preload, results appear after the first user interaction (e.g., opening a filter dropdown).
Named Instance
Configure a specific instance:
Programmatic Configuration
For complex configuration, use JavaScript instead of the `` element:
<script>
const { configureInstance } = window.PagefindComponents;
configureInstance("default", {
bundlePath: "/pagefind/",
mergeIndex: [
{ bundlePath: "/other-site/pagefind/" }
],
ranking: {
termFrequency: 0.8
}
});
</script>Either place this on the page as shown, or compile it into your existing JavaScript bundle.
See Pagefind Search Config for all available options.
File: docs/content/docs/components/filter-dropdown.md
title: "" nav_title: "" nav_section: Components weight: 90
A dropdown selector for a single filter.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
filter |
string | β | Required. The filter key to display |
label |
string | filter name | Text shown on the trigger button |
single-select |
boolean | false |
Allow only one selection (closes after selecting) |
show-empty |
boolean | false |
Show options with zero results |
wrap |
boolean | false |
Allow text to wrap to multiple lines |
sort |
string | "default" |
Sort filter values: default, alphabetical, count-desc, count-asc |
hide-clear |
boolean | false |
Hide the adjacent "Clear" button |
instance |
string | "default" |
Connect to a specific Pagefind instance |
Keyboard Navigation
Full keyboard support following the ARIA Listbox pattern:
| Key | Action |
|---|---|
β / β |
Navigate through options |
Home / End |
Jump to first/last option |
Enter / Space |
Toggle selection |
Escape |
Close dropdown |
Tab |
Close and move focus |
| Type characters | Jump to matching option (type-ahead) |
Type-Ahead Behavior
When you type characters while the dropdown is open:
- The component jumps to the first option that starts with the typed characters
- Matching is case-insensitive
- The type buffer clears after 500ms of inactivity
Faceted Search Mode
For catalog-style interfaces where users browse by filters without requiring a search term, enable faceted mode via ``:
In faceted mode, all results are shown initially and update immediately when filters are changed. See the config component documentation for details.
File: docs/content/docs/components/filter-pane.md
title: "" nav_title: "" nav_section: Components weight: 80
A full filter panel displaying all available filters. Filters automatically populate based on your indexed content.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
show-empty |
boolean | false |
Show filter options with zero results |
expanded |
boolean | false |
Always show groups expanded (non-collapsible) |
open |
string | "" |
Comma-separated filter names to start open |
sort |
string | "default" |
Sort filter values: default, alphabetical, count-desc, count-asc |
auto-open-threshold |
number | 6 |
Max values for auto-opening single groups (0 to disable) |
instance |
string | "default" |
Connect to a specific Pagefind instance |
Auto-open Behavior
By default, filter groups are collapsible. If there is only one group, and it has options at or below the auto-open-threshold, it will open automatically.
Groups can also be opened by listing their keys in the open attribute.
Filter Visibility
- Options with zero matching results are hidden by default (unless
show-emptyis set or the option is selected) - If all options in a group are hidden, the entire group is hidden
Faceted Search Mode
For catalog-style interfaces where users browse by filters without requiring a search term, enable faceted mode via ``:
In faceted mode, all results are shown initially and update immediately when filters are changed. See the config component documentation for details.
File: docs/content/docs/components/input.md
title: "" nav_title: "" nav_section: Components weight: 10
A search input field with debouncing.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
placeholder |
string | Language dependent | Placeholder text shown when input is empty |
debounce |
number | 300 |
Milliseconds to wait after typing before searching |
autofocus |
boolean | false |
Focus input when page loads |
instance |
string | "default" |
Connect to a specific Pagefind instance |
Behavior
- Focusing the input begins loading the Pagefind search bundle
- When search is triggered by other components, this input's value is automatically updated
- When focused, the input registers keyboard shortcuts with the instance
Keyboard Behavior
| Key | Action |
|---|---|
Escape |
Clear the input and reset search |
β |
Move focus to the results list |
File: docs/content/docs/components/keyboard-hints.md
title: "" nav_title: "" nav_section: Components weight: 50
Displays contextual keyboard shortcuts based on which component currently has focus.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
instance |
string | "default" |
Connect to a specific Pagefind instance |
How It Works
Keyboard hints are contextual. Different components register their shortcuts when focused:
| Component Focus | Shortcuts Shown |
|---|---|
| Input | β navigate, esc clear |
| Results | ββ navigate, β΅ select, / search |
| Modal | esc close |
When no component has focus, the keyboard hints area is empty.
Accessibility
This component is marked aria-hidden="true" because it's a visual aid for sighted keyboard users.
The Component UI shortcuts are either the expected controls for WAI-ARIA patterns, or they are optional alternatives to standard tab navigation patterns.
Touch Devices
Keyboard hints are automatically hidden on touch-only devices.
File: docs/content/docs/components/modal.md
title: "" nav_title: "" nav_section: Components weight: 40
A modal overlay container for search. Opens over the page content and traps focus until closed. Users can close it by pressing Escape, clicking the backdrop, or using the close button in the header (visible on mobile).
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
reset-on-close |
boolean | false |
Clear the search input when modal closes |
instance |
string | "default" |
Connect to a specific Pagefind instance |
Default Structure
When used without child elements, the modal auto-generates a default structure:
If you want to customize the contents of your own modal, the above is a good starting point.
Structure Components
The modal uses three structural components. These are optional if you're providing your own modal contents, but it's recommended to place your components within them.
``
Fixed header area that stays pinned to the top of the modal. Typically contains the search input. Automatically includes a close button that is visible on mobile viewports.
``
Scrollable content area for results and other search content. Scroll is contained within this element so the header and footer remain visible.
``
Optional fixed footer area, pinned to the bottom of the modal. Typically contains keyboard hints or other supplementary information.
File: docs/content/docs/components/modal-trigger.md
title: "" nav_title: "" nav_section: Components weight: 60
A button that opens the associated modal.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
placeholder |
string | Language dependent | Text shown on the trigger button |
shortcut |
string | "mod+k" |
Keyboard shortcut to open modal |
hide-shortcut |
boolean | false |
Hide the keyboard shortcut display |
compact |
boolean | false |
Show only the search icon, no text |
instance |
string | "default" |
Connect to a specific Pagefind instance |
Keyboard Shortcut
By default, the trigger listens for Cmd+K (Mac) or Ctrl+K (Windows/Linux) to open the modal. The keyboard listener is attached at the document level, so the shortcut works from anywhere on the page.
Customizing the Shortcut
You can customize the keyboard shortcut using the shortcut attribute:
Example with / key:
Supported syntax:
- Platform modifier:
mod(Ctrl on Windows/Linux, Cmd on Mac) - Explicit modifiers:
ctrl,shift,alt,cmd/meta - Keys: Any single character (e.g.
k,/) or key name - Case-insensitive: Keys are normalized to lowercase
The shortcut display auto-detects the platform to show the correct modifier key (β on Mac, Ctrl on other platforms).
File: docs/content/docs/components/results.md
title: "" nav_title: "" nav_section: Components weight: 20
Displays search results with automatic lazy loading. Results load their full data only when scrolled into view.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
show-images |
boolean | false |
Show/hide result images |
hide-sub-results |
boolean | false |
Hide anchor-based sub-results |
max-sub-results |
number | 3 |
Maximum number of sub-results per result |
max-results |
number | unlimited | Limit number of results shown |
link-target |
string | β | Set target attribute on result links (e.g., _blank for new tab) |
instance |
string | "default" |
Connect to a specific Pagefind instance |
Keyboard Navigation
When results are focused, use these keys to navigate:
| Key | Action |
|---|---|
β / β |
Navigate between results |
Enter |
Follow the selected link |
Backspace |
Focus input and delete last character |
/ |
Focus the search input |
| Any letter | Focus input and type the character |
Custom Templates
Customize result rendering using <script type="text/pagefind-template"> elements inside the component. Templates use a simple syntax with variables, conditionals, and loops.
Basic Template
<script type="text/pagefind-template">
<li class="my-result">
<h3>{{ meta.title }}</h3>
[{{ url }}]({{ url | safeUrl }})
{{+ excerpt +}}
</li>
</script>Your template must have a single root element (e.g. a single <li>). Keyboard navigation moves between <a> elements in the results list, so ensure your main result link is an <a> tag.
The full templating syntax can be seen in the adequate-little-templates package.
Available Data
Templates receive this data structure:
| Field | Description |
|---|---|
meta.title |
Page title |
meta.url |
Page URL |
meta.image |
Page image (if set) |
meta.image_alt |
Image alt text |
meta.* |
Any custom metadata |
excerpt |
Search excerpt with <mark> highlighting (use {{+ excerpt +}}) |
url |
Fallback URL |
sub_results |
Array of matching sections within the page |
options.* |
The attributes supplied to the `` element |
Each sub-result has: title, url, excerpt.
Template Filters
The template engine provides built-in filters. The Component UI registers the following additional filters:
`resolveUrl(pageUrl)`
Resolves a relative URL against a page URL. Absolute URLs are returned unchanged.
"images/hero.png" | resolveUrl("/blog/post/") β /blog/post/images/hero.pngPlaceholder Template
While results are loading, a skeleton placeholder is shown. You can customize it with a second template using data-template="placeholder", as shown in the full example below. The placeholder template receives no data β it is static HTML.
Full Template Example
Here's the built-in template. Copy and customize it:
<script type="text/pagefind-template">
<li class="pf-result">
{{#if and(options.show_images, meta.image)}}
{{/if}}
<a class="pf-result-link" href="{{ meta.url | default(url) | safeUrl }}"{{#if options.link_target}} target="{{ options.link_target }}"{{/if}}{{#if eq(options.link_target, "_blank")}} rel="noopener"{{/if}}>{{ meta.title }}</a>
{{#if excerpt}}
{{+ excerpt +}}
{{/if}}
{{#if sub_results}}
{{#each sub_results as sub}}
<li class="pf-heading-chip">
<a class="pf-heading-link" href="{{ sub.url | safeUrl }}"{{#if options.link_target}} target="{{ options.link_target }}"{{/if}}{{#if eq(options.link_target, "_blank")}} rel="noopener"{{/if}}>{{ sub.title }}</a>
{{+ sub.excerpt +}}
</li>
{{/each}}
{{/if}}
</li>
</script>
<script type="text/pagefind-template" data-template="placeholder">
<li class="pf-result" aria-hidden="true">
</li>
</script>Results Layout
By default, results display in a single column. You can change the layout of the results container using CSS variables, for example a grid layout:
:root {
--pf-results-display: grid;
--pf-results-columns: repeat(auto-fill, minmax(250px, 1fr));
--pf-results-gap: 16px;
}See CSS Variables for all available layout variables.