Bryan Hamilton / projects / instant-search-index

bryanhamilton.info / open source / instant-search-index

instant-search-index Type. It's already there.

The search from The DJ Calendar, extracted as a standalone widget. The index ships with the page as JSON and is scored in the browser on every keystroke, so results feel instant because they are: there's no network left to wait on.

  • Zero dependencies
  • Zero server round-trips
  • ARIA combobox
  • MIT license
In brief: instant-search-index is a zero-dependency JavaScript search widget that ranks a prebuilt JSON index in the browser on each query. Weighted AND matching, keyboard navigation, and ARIA combobox semantics provide useful results without a search server or search-time network requests.

Search the DJ Mag Top 100

The real list from thedjcalendar.com, searched the way the site does it

Try:

Showing all 99 DJs

David GuettaDJ Mag Top 100 Martin GarrixDJ Mag Top 100 AlokDJ Mag Top 100 Dimitri Vegas and Like MikeDJ Mag Top 100 Armin van BuurenDJ Mag Top 100 Timmy TrumpetDJ Mag Top 100 FISHERDJ Mag Top 100 AfrojackDJ Mag Top 100 Charlotte de WitteDJ Mag Top 100 AnymaDJ Mag Top 100 Vintage CultureDJ Mag Top 100 Peggy GouDJ Mag Top 100 Don DiabloDJ Mag Top 100 Steve AokiDJ Mag Top 100 HardwellDJ Mag Top 100 Calvin HarrisDJ Mag Top 100 Black CoffeeDJ Mag Top 100 Lost FrequenciesDJ Mag Top 100 KeinemusikDJ Mag Top 100 TiëstoDJ Mag Top 100 Reinier ZonneveldDJ Mag Top 100 KSHMRDJ Mag Top 100 Alan WalkerDJ Mag Top 100 Carl CoxDJ Mag Top 100 Oliver HeldensDJ Mag Top 100 Jamie JonesDJ Mag Top 100 R3habDJ Mag Top 100 Nicky RomeroDJ Mag Top 100 ClaptoneDJ Mag Top 100 SkrillexDJ Mag Top 100 Vini ViciDJ Mag Top 100 Fred again...DJ Mag Top 100 Swedish House MafiaDJ Mag Top 100 Joel CorryDJ Mag Top 100 Indira PaganottoDJ Mag Top 100 Eric PrydzDJ Mag Top 100 Amelie LensDJ Mag Top 100 Paul van DykDJ Mag Top 100 DJ SnakeDJ Mag Top 100 Dom DollaDJ Mag Top 100 MarshmelloDJ Mag Top 100 The Martinez BrothersDJ Mag Top 100 ZeddDJ Mag Top 100 BassjackersDJ Mag Top 100 John SummitDJ Mag Top 100 QuintinoDJ Mag Top 100 Michael BibiDJ Mag Top 100 Boris BrejchaDJ Mag Top 100 KorolovaDJ Mag Top 100 AlessoDJ Mag Top 100 James HypeDJ Mag Top 100 MaddixDJ Mag Top 100 HUGELDJ Mag Top 100 SolomunDJ Mag Top 100 MochakkDJ Mag Top 100 Lilly PalmerDJ Mag Top 100 Nora En PureDJ Mag Top 100 ATBDJ Mag Top 100 Deborah De LucaDJ Mag Top 100 Above & BeyondDJ Mag Top 100 Sara LandryDJ Mag Top 100 NervoDJ Mag Top 100 Sub Zero ProjectDJ Mag Top 100 KölschDJ Mag Top 100 Lucas & SteveDJ Mag Top 100 Nico MorenoDJ Mag Top 100 GORDODJ Mag Top 100 PAWSADJ Mag Top 100 The ChainsmokersDJ Mag Top 100 LiuDJ Mag Top 100 Mike WilliamsDJ Mag Top 100 ARTBATDJ Mag Top 100 KAAZEDJ Mag Top 100 Miss MoniqueDJ Mag Top 100 Burak YeterDJ Mag Top 100 Mau PDJ Mag Top 100 Le TwinsDJ Mag Top 100 I Hate ModelsDJ Mag Top 100 MarnikDJ Mag Top 100 Chris StussyDJ Mag Top 100 Deadmau5DJ Mag Top 100 WUKONGDJ Mag Top 100 Fedde Le GrandDJ Mag Top 100 Ferry CorstenDJ Mag Top 100 Plastik FunkDJ Mag Top 100 DubVisionDJ Mag Top 100 B JonesDJ Mag Top 100 Giuseppe OttavianiDJ Mag Top 100 CuebrickDJ Mag Top 100 Mariana BoDJ Mag Top 100 MEDUZADJ Mag Top 100 FantasmDJ Mag Top 100 VINAIDJ Mag Top 100 Chris LakeDJ Mag Top 100 FaustixDJ Mag Top 100 Honey DijonDJ Mag Top 100 Nils van ZandtDJ Mag Top 100 TopicDJ Mag Top 100 Marlon HoffstadtDJ Mag Top 100

The opinion underneath it

Most search boxes are infrastructure cosplay: a request to a search endpoint, a spinner, a payload, all for what is usually a list of a few hundred names that the page could have shipped with in the first place.

This project's stance: if the catalog fits in the page, the search belongs in the page. Ship the index as JSON, score it in the browser on every keystroke, and there's nothing left to wait for. No search server, no framework, no library, one file. On The DJ Calendar, that's how site search has worked across roughly 1,000 pages.

The demo above proves the point in the counter under the search box: every keystroke rescores all 99 DJs in a fraction of a millisecond, and the network request count stays at zero.

How records are scored

Every keystroke scores every record. A record has to match every word you type somewhere, or it drops out (AND matching), so "house mafia" finds Swedish House Mafia and nothing else. Where each match lands decides the rank:

SignalWeightExample
Title word, exact60"cox" hits Carl Cox
Title word, prefix40"ame" hits Amelie Lens
Keyword, exact30"techno" hits the genre field
Keyword, prefix18"tech" hits "techno"
Subtitle, exact / prefix12 / 8useful, but not the point
Loose substring4the safety net
Full-phrase bonus+25"black coffee" beats token soup

Ties go to the shorter title, so "Carl Cox" outranks a longer name that matches equally well, then to index order, which keeps results stable as you type. Tokens are precomputed once at load, so a keystroke scores arrays and never re-splits strings. Accents are folded too, which is why "tiesto" finds Tiësto and "kolsch" finds Kölsch.

The demo scores with the weights documented in the repo's README. Tick "Show how each result scored" above to see the math for each result.

The index contract

One JSON array. Three searchable fields and two display-only ones:

{
  "title":    "Carl Cox",
  "subtitle": "Techno / House",
  "keywords": "techno house icon ibiza space",
  "badge":    "Artist",
  "url":      "/artists/carl-cox"
}

title is required and weighted heaviest. subtitle is lightly searchable. keywords is the synonym field: genres, cities, nicknames, anything your visitors type that isn't in the title. badge is a display-only tag, and url is where Enter goes.

The production trick: the server renders the index once when the page is built, so the browser never fetches anything at search time. Search-time network work is zero, and the only payload is data the page wanted anyway.

Keyboard and ARIA, first-class

The input is a real ARIA combobox: role="combobox", aria-expanded, aria-controls and aria-activedescendant pointing into a role="listbox" of options, so screen readers announce the highlighted result as you move. Put the mouse away and try it on the demo:

KeyWhat it does
↓ / ↑Move the highlighted result
EnterOpen the highlighted result, or go straight there if there's only one
EscapeClose the list

Matched text is highlighted with <mark>, and everything is escaped before it's rendered: index entries are treated as data, never as markup.

Use it in your project

Declarative: the index travels in an attribute and the widget builds itself.

<link rel="stylesheet" href="src/search.css">
<script src="src/search.js" defer></script>

<input type="text" data-instant-search='[
  {"title": "Carl Cox", "subtitle": "Techno", "keywords": "techno house icon", "badge": "Artist", "url": "/artists/carl-cox"},
  {"title": "Amelie Lens", "subtitle": "Techno", "keywords": "techno belgium", "badge": "Artist", "url": "/artists/amelie-lens"}
]'>

Programmatic, for records that live in JavaScript or arrive at runtime:

InstantSearch.attach(inputEl, records, { maxResults: 6, placeholder: "Find an artist..." });

From the repo's README. Options include minLength (default 2), maxResults (8), debounce (80 ms), emptyMessage and placeholder. Any browser from the last decade, no build step.

Frequently asked questions

How does instant-search-index search without a server?

The page carries a prebuilt JSON array, and the browser scores those records locally as the visitor types. Search queries make no server round-trips.

How are search results ranked?

Every query token must match somewhere in a record. Exact and prefix matches in titles and keywords receive different weights, full-phrase matches get a bonus, and ties remain stable.

Can I use the search with a keyboard?

Yes. The input is an ARIA combobox: Arrow Up and Arrow Down move through options, Enter selects, and Escape closes the list.

What fields does an index record support?

Each record requires a title and can include a searchable subtitle and keywords plus a display badge and destination URL.

Need search that just feels fast?

Bryan Hamilton is a full-stack web engineer with 25+ years in PHP and JavaScript, available immediately for remote, hybrid or on-site roles in the NYC metro area.