Skip to content

Commit 5cdd3ac

Browse files
e-krebsclaude
andcommitted
chore: add autocomplete-multifeed JS example
Demonstrates the new `feeds` option on `EXPERIMENTAL_autocomplete` with a composition-backed autocomplete panel (query suggestions + products + articles feeds from a single multifeed response). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 311f52b commit 5cdd3ac

7 files changed

Lines changed: 264 additions & 0 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# InstantSearch.js — Autocomplete multifeed
2+
3+
Showcases `EXPERIMENTAL_autocomplete` in **feeds-mode**: one composition
4+
request drives all panel sections instead of one search call per section.
5+
6+
## Backend requirement
7+
8+
This example hits a composition named `comp1774447423386___products` on the
9+
`9HILZG6EJK` Algolia app. It returns three feeds: `products`, `Fashion`, and
10+
`Amazon`. To run this against a different backend, replace `searchClient` and
11+
`compositionID` in `src/app.ts` with your own composition.
12+
13+
## Run
14+
15+
From the repo root:
16+
17+
```sh
18+
yarn workspace example-instantsearch-autocomplete-multifeed dev
19+
```
20+
21+
Open the URL the dev server prints and start typing. DevTools' Network tab
22+
should show **exactly one** composition call per keystroke — regardless of
23+
how many sections the panel renders.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta
6+
name="viewport"
7+
content="width=device-width, initial-scale=1, shrink-to-fit=no"
8+
/>
9+
<base href="%BASE_URL%" />
10+
<link rel="stylesheet" href="./src/app.css" />
11+
<title>InstantSearch.js — Autocomplete multifeed</title>
12+
</head>
13+
14+
<body>
15+
<header class="header">
16+
<h1 class="header-title">
17+
<a href="/">Autocomplete multifeed</a>
18+
</h1>
19+
<p class="header-subtitle">
20+
using
21+
<a href="https://github.com/algolia/instantsearch">
22+
InstantSearch.js
23+
</a>
24+
</p>
25+
</header>
26+
27+
<div class="container">
28+
<main>
29+
<div class="container-wrapper">
30+
<div class="search-panel">
31+
<div class="search-panel__results">
32+
<div id="autocomplete"></div>
33+
<div id="hits"></div>
34+
<div id="pagination"></div>
35+
</div>
36+
</div>
37+
</div>
38+
</main>
39+
</div>
40+
41+
<script type="module" src="./src/app.ts"></script>
42+
</body>
43+
</html>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "example-instantsearch-autocomplete-multifeed",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"dev": "vite",
7+
"start": "vite",
8+
"build": "vite build",
9+
"preview": "vite preview",
10+
"website:examples": "vite build --outDir ../../../website/examples/js/autocomplete-multifeed --base /examples/js/autocomplete-multifeed"
11+
},
12+
"dependencies": {
13+
"@algolia/composition": "1.25.1",
14+
"algoliasearch-helper": "3.28.1",
15+
"instantsearch-ui-components": "0.23.0",
16+
"instantsearch.css": "8.13.0",
17+
"instantsearch.js": "4.93.0"
18+
},
19+
"devDependencies": {
20+
"vite": "5.0.7",
21+
"vite-plugin-commonjs": "0.10.0"
22+
}
23+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
:root {
2+
--ais-primary-color-rgb: 200, 130, 10;
3+
}
4+
5+
body,
6+
h1 {
7+
margin: 0;
8+
padding: 0;
9+
}
10+
11+
body {
12+
font-family:
13+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica,
14+
Arial, sans-serif;
15+
}
16+
17+
.header {
18+
display: flex;
19+
align-items: center;
20+
min-height: 50px;
21+
padding: 0.5rem 1rem;
22+
background-image: linear-gradient(284deg, #fedd4e, #fcb43a);
23+
color: #fff;
24+
margin-bottom: 1rem;
25+
}
26+
27+
.header a {
28+
color: #fff;
29+
text-decoration: none;
30+
}
31+
32+
.header-title {
33+
font-size: 1.2rem;
34+
font-weight: normal;
35+
}
36+
37+
.header-title::after {
38+
content: ' ▸ ';
39+
padding: 0 0.5rem;
40+
}
41+
42+
.header-subtitle {
43+
font-size: 1.2rem;
44+
}
45+
46+
.container {
47+
max-width: 1200px;
48+
margin: 0 auto;
49+
padding: 1rem;
50+
}
51+
52+
.search-panel {
53+
display: flex;
54+
}
55+
56+
.search-panel__results {
57+
flex: 3;
58+
}
59+
60+
#pagination {
61+
margin: 2rem auto;
62+
text-align: center;
63+
}
64+
65+
.ais-Highlight-highlighted {
66+
color: inherit;
67+
font-size: inherit;
68+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { compositionClient } from '@algolia/composition';
2+
import instantsearch from 'instantsearch.js';
3+
import {
4+
configure,
5+
EXPERIMENTAL_autocomplete,
6+
hits,
7+
pagination,
8+
} from 'instantsearch.js/es/widgets';
9+
10+
import 'instantsearch.css/themes/satellite.css';
11+
12+
const searchClient = compositionClient(
13+
'9HILZG6EJK',
14+
'65b3e0bb064c4172c4810fb2459bebd1'
15+
);
16+
17+
const compositionID = 'comp1774447423386___products';
18+
19+
const search = instantsearch({
20+
// @ts-expect-error compositionClient return type doesn't fully match SearchClient yet
21+
searchClient,
22+
compositionID,
23+
insights: true,
24+
});
25+
26+
search.addWidgets([
27+
configure({ hitsPerPage: 8 }),
28+
EXPERIMENTAL_autocomplete({
29+
container: '#autocomplete',
30+
placeholder: 'Search for products',
31+
feeds: [
32+
{
33+
feedID: 'products',
34+
templates: {
35+
header: (_, { html }) => html`
36+
<span class="ais-AutocompleteIndexHeaderTitle">Products</span>
37+
<span class="ais-AutocompleteIndexHeaderLine" />
38+
`,
39+
item: ({ item, onSelect }, { html }) => html`
40+
<div onClick=${onSelect}>${(item as any).title}</div>
41+
`,
42+
},
43+
},
44+
{
45+
feedID: 'Fashion',
46+
templates: {
47+
header: (_, { html }) => html`
48+
<span class="ais-AutocompleteIndexHeaderTitle">Fashion</span>
49+
<span class="ais-AutocompleteIndexHeaderLine" />
50+
`,
51+
item: ({ item, onSelect }, { html }) => html`
52+
<div onClick=${onSelect}>${(item as any).name}</div>
53+
`,
54+
},
55+
},
56+
{
57+
feedID: 'Amazon',
58+
templates: {
59+
header: (_, { html }) => html`
60+
<span class="ais-AutocompleteIndexHeaderTitle">Amazon</span>
61+
<span class="ais-AutocompleteIndexHeaderLine" />
62+
`,
63+
item: ({ item, onSelect }, { html }) => html`
64+
<div onClick=${onSelect}>${(item as any).product_title}</div>
65+
`,
66+
},
67+
},
68+
],
69+
showRecent: {
70+
templates: {
71+
header: (_, { html }) => html`
72+
<span class="ais-AutocompleteIndexHeaderTitle">Recent Searches</span>
73+
<span class="ais-AutocompleteIndexHeaderLine" />
74+
`,
75+
},
76+
},
77+
}),
78+
hits({
79+
container: '#hits',
80+
templates: {
81+
item: (hit, { html, components }) => html`
82+
<article>
83+
<h1>${components.Highlight({ hit, attribute: 'title' })}</h1>
84+
<p>${(hit as any).author?.join?.(', ')}</p>
85+
</article>
86+
`,
87+
},
88+
}),
89+
pagination({
90+
container: '#pagination',
91+
}),
92+
]);
93+
94+
search.start();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { defineConfig } from 'vite';
2+
import commonjs from 'vite-plugin-commonjs';
3+
4+
export default defineConfig({
5+
plugins: [commonjs()],
6+
build: {
7+
commonjsOptions: {
8+
requireReturnsDefault: 'preferred',
9+
},
10+
},
11+
});

tsconfig.v4.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"examples/react/next-routing",
1111
"examples/react/next-app-router",
1212
"examples/react/react-native",
13+
// @algolia/composition is not compatible with algoliasearch v4.
14+
"examples/js/autocomplete-multifeed",
1315
"examples/js/e-commerce-umd/public/packages",
1416
"packages/create-instantsearch-app/src/templates/**/*",
1517
"packages/algolia-experiences"

0 commit comments

Comments
 (0)