Search
An instant search UI component for the Web aimed to be light, agnostic and effective.
Features
- instant search
- highlight search term matches
- show match context
- easy to install
- runs locally on the browser
- not overly complicated
- does not require any kind of framework or tooling
- Fuse.js is the sole dependency
- works when offline (DocSearch doesn't)
- works behind authentication (DocSearch doesn't)
- do not track users (DocSearch doesn't?)
- acessibility (please fill a report if it doesn't work properly with screen readers)
Caveats
- It does not support context-wise search at headings level as DocSearch does.
- Fuse.js is kind of dead.
Demo
Check the demo. It uses Hugo.
Usage
Data
It expects JSON data at /index.json
but this can be changed with dataPath
option.
Expected keys are title
, description
, url
, image
(optional) and id
(optional).
{
"id": "3db3e4a737a176646e0c3b8d5f25d392",
"url": "/lorem-ipsum/",
"title": "Lorem Ipsum"
}
,
{
"id": "e62701a89b303de6e24cb577ee9d5614",
"url": "/dolor-sit-amet/",
"title": "Dolor Sit Amet"
}
Use
import Search from 'lite-search'
Search({
// comment keys that aren't going to be used.
keys: [
{ name: "title", weight: 7 },
{ name: "description", weight: 3 },
{ name: "content", weight: 1 }
],
// optionally provide an alias when key names on JSON differ from what the script expects.
aliases: [
// { input: "title", output: "description" },
// { input: "description", output: "title" }
],
dataPath: "/index.json",
// dataPath: "/" + basePath + lang + "/index.json", // for multilingual
formSelector: "#search",
minInputLength: 0,
matchStrategy: "fuzzy",
maxResults: 10,
maxContextLength: 250,
includeMatches: false, // NOTE: use 'exact' for matchStrategy
showSectionOnTitle: true,
modalFullscreen: false
})
Use NPM with a bundler like ESBuild. Or, as in the case of Hugo, use it's JS Building feature to build a script. If you can't or don't want to use NPM you can use the pre-bundled (lite-search + fuse.js) distributables at dist/
.
<script src="./lite-search/dist/search.js" async></script>
When the call and the script are enclosed together (bundled) they can be loaded asynchronously, otherwise you will have to defer the call until the script is loaded.
<script src="./lite-search/dist/search.js" async></script>
<script defer>
Search({})
....
</script>
HTML
<form id="search" role="search" aria-haspopup="listbox" aria-labelledby="search-label" hidden="true">
<label id="search-label" class="fas fa-search"></label>
<input
id="search-input"
type="search"
list="search-results"
placeholder="Search..."
aria-label="Search"
autocomplete="off"
spellcheck="false"
hidden="true"
>
</input>
<ul id="search-modal" role="listbox" hidden="true">
</ul>
</form>