astro-fuse
v2.0.1
Published
Use Fuse.js to search documents in your Astro site
Downloads
472
Maintainers
Readme
astro-fuse

This Astro integration generates the fuse.json index file of Fuse.js when your Astro project during build.
Use this plugin to add content search functionality to your Astro site.
Compatibility
| astro-fuse | Supported Astro | Modes | Status |
| ------------ | ------------------- | ------------------------------ | ------------------------------------------- |
| 2.x | Astro >=5 | output only | Active (tested on Astro 7) |
| 1.x | Astro 4 – 5 | output (4–5), source (4) | Maintenance only |
2.x requires Astro 5 or later. It adapts to two changes in the Astro 5/6 cycle:
- Astro 5 deprecated the
routesfield on theastro:build:donehook and Astro 6 removed it.2.xreads route data from theastro:routes:resolvedhook (added in Astro 5) instead. This is why1.xkeeps working through Astro 5 but breaks on Astro 6+ — those users need2.x. - Astro 5's Content Layer no longer routes content files through Vite's
transformhook, which the oldbasedOn: 'source'mode depended on. Source mode was removed in2.x(it only ever worked on Astro 4); output mode is the only mode.
On Astro 4 use astro-fuse@1. On Astro 5 either line works (2.x recommended). On Astro 6+ use astro-fuse@2.
Usage
First, install the astro-fuse packages using your package manager.
npx astro add astro-fuse
pnpm astro add astro-fuse
yarn astro add astro-fuseThen, apply this integration to your astro.config.* file using the integrations properly.
// astro.config.mjs
import { defineConfig } from 'astro/config'
import fuse from 'astro-fuse'
export default defineConfig({
integrations: [fuse(['content'])],
})When you install the integration, you can add search component on a page.
You need run
astro buildbefore using it. for detailed explanations, please refer to the remarks section below.
<!-- Search.astro -->
<custom-search>
<input data-search-inp type="text" />
<ul data-search-result></ul>
</custom-search>
<script>
import type { OutputBaseSearchable } from 'astro-fuse'
class CustomSearch extends HTMLElement {
list = this.querySelector<HTMLUListElement>('[data-search-result]')
constructor() {
super()
this.querySelector<HTMLInputElement>(
'[data-search-inp]'
)?.addEventListener('input', this.onInput.bind(this))
}
async onInput(e: Event) {
const { list } = this
if (!list) {
return
}
// create fuse instance from index
const { loadFuse } = await import('astro-fuse/client')
const fuse = await loadFuse()
const results = fuse.search<OutputBaseSearchable>((e.target as HTMLInputElement).value.trim())
list.innerHTML = results
.map(
({ item }) =>
`<li><a href="${item.pathname}">${item.frontmatter.title}</a></li>`
)
.join('')
}
}
customElements.define('custom-search', CustomSearch)
</script>You can also just load and use the index file as shown in the example below.
Since the size of the index file can be large depending on the settings, it is recommended to lazy-load the index file.
<!-- Search.astro -->
<script>
import Fuse from 'fuse.js'
fetch('/fuse.json')
.then(res => res.json())
.then(({index, list}) => {
const fuse = new Fuse(list, undefined, Fuse.parseIndex(index))
fuse.search('...')
})
</script>Methods and Options
fuse(keys, [options])
keys
You can provide the key values of the properties you want to search in addition to the body.
The index is generated from the HTML files produced by your build, so you can search the static rendering results of components used in your Markdown/MDX pages.
Removed in v2: the
basedOn: 'source'mode was removed. It relied on Vite transforming content files, which no longer happens with Astro 5's Content Layer. Use the default (output) mode.
filename
The file name of the index file to be generated.
filter
All HTML files generated as a result of the build are subject to search index generation. If you want to restrict this, use the filter option.
// astro.config.mjs
fuse(['content', 'frontmatter.title'], {
filter: (path) => /^\/post\/[^/]+\/$/.test(path),
})extractContentFromHTML
The index is generated from the HTML files produced by the build. This may include unnecessary content such as text in the header area. You can use the extractContentFromHTML option to select the elements that need to be searched.
// astro.config.mjs
// ...
fuse(
['content', 'frontmatter.title'],
{
extractContentFromHTML: 'article' // index text inner <article> element.
extractContentFromHTML: $ => $('div#content') // or. you can use cheerio instance.
}
)extractFrontmatterFromHTML
The index is generated from the rendered HTML files, so frontmatter cannot be extracted directly. If frontmatter is required, you can use the extractFrontmatterFromHTML option to make frontmatter searchable as well.
For example, if you need the original title value because the pathname is sluggified, the following MDX file can be bundled into various path HTML files like /content/2023-08-14-a-page-title.mdx => blog/2023/08/a-page-title.html.
---
title: A Page Title
---In this situation, the extractFrontmatterFromHTML option can be helpful. If you render the title to the meta[property="og:title"] tag, you can get it with the following options.
// astro.config.mjs
fuse(['content', 'frontmatter.title'], {
extractFrontmatterFromHTML: ($) => {
// read that element value. $ is cheerio instance.
const el = $('[data-frontmatter]')
if (el.length) {
return JSON.parse(el.first().val())
}
return { title: $('h1').first().text() }
},
})<!-- [slug].astro -->
---
const { frontmatter } = Astro.props;
---
<html>
<!-- .. make hidden input for render frontmatter .. -->
<input
type="hidden"
data-frontmatter
value={JSON.stringify(frontmatter)}
/>
</html>The $ is a Cheerio instance, and you can use it to search for elements. For more information, see the Selecting Elements links. Selecting Elements
loadFuse([options])
url
The path to the index file to be used as the first argument of fetch.
init
A RequestInit object containing any custom settings that you want to apply to the request.
See fetch options
options
The option object used when creating a Fuse.js instance.
See Fuse.js options
Example
Remarks
- In a development environment, the index file for Fuse.js may not be created immediately when the server starts. In this case, you can request a page that uses a Markdown file to trigger the build process. Please note that the file is created immediately in the production build stage. If it is not created, please report an issue.
