Skip to content

Commit 7a0eba4

Browse files
e-krebsclaude
andcommitted
chore: add autocomplete-multifeed React example
Mirrors the JS example: a composition-backed autocomplete panel driven by the new `feeds` prop on `EXPERIMENTAL_Autocomplete`, with query suggestions and per-feed result sections from a single multifeed composition response. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5cdd3ac commit 7a0eba4

8 files changed

Lines changed: 318 additions & 0 deletions

File tree

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: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import { compositionClient } from '@algolia/composition';
2+
import React from 'react';
3+
import {
4+
Configure,
5+
EXPERIMENTAL_Autocomplete,
6+
Highlight,
7+
Hits,
8+
InstantSearch,
9+
Pagination,
10+
} from 'react-instantsearch';
11+
12+
import 'instantsearch.css/themes/satellite.css';
13+
import './App.css';
14+
15+
import type { Hit as AlgoliaHit } from 'instantsearch.js';
16+
17+
const searchClient = compositionClient(
18+
'9HILZG6EJK',
19+
'65b3e0bb064c4172c4810fb2459bebd1'
20+
);
21+
22+
const compositionID = 'comp1774447423386___products';
23+
24+
type ProductHit = AlgoliaHit<{
25+
title: string;
26+
author?: string[];
27+
largeImage: string;
28+
}>;
29+
30+
type FashionHit = AlgoliaHit<{
31+
name: string;
32+
image: string;
33+
brand: string;
34+
price: number;
35+
currency: string;
36+
}>;
37+
38+
type AmazonHit = AlgoliaHit<{
39+
product_title: string;
40+
product_brand: string;
41+
}>;
42+
43+
export function App() {
44+
return (
45+
<div>
46+
<header className="header">
47+
<h1 className="header-title">
48+
<a href="/">Autocomplete multifeed</a>
49+
</h1>
50+
<p className="header-subtitle">
51+
using{' '}
52+
<a href="https://github.com/algolia/instantsearch/tree/master/packages/react-instantsearch">
53+
React InstantSearch
54+
</a>
55+
</p>
56+
</header>
57+
58+
<div className="container">
59+
<InstantSearch
60+
// @ts-expect-error compositionClient return type doesn't fully match SearchClient yet
61+
searchClient={searchClient}
62+
compositionID={compositionID}
63+
insights={true}
64+
>
65+
<Configure hitsPerPage={8} />
66+
67+
<main>
68+
<div className="container-wrapper">
69+
<div className="search-panel">
70+
<div className="search-panel__results">
71+
<EXPERIMENTAL_Autocomplete
72+
placeholder="Search for products"
73+
feeds={[
74+
{
75+
feedID: 'products',
76+
headerComponent: () => (
77+
<>
78+
<span className="ais-AutocompleteIndexHeaderTitle">
79+
Products
80+
</span>
81+
<span className="ais-AutocompleteIndexHeaderLine" />
82+
</>
83+
),
84+
itemComponent: ({ item, onSelect }) => (
85+
<div onClick={onSelect}>
86+
{(item as ProductHit).title}
87+
</div>
88+
),
89+
},
90+
{
91+
feedID: 'Fashion',
92+
headerComponent: () => (
93+
<>
94+
<span className="ais-AutocompleteIndexHeaderTitle">
95+
Fashion
96+
</span>
97+
<span className="ais-AutocompleteIndexHeaderLine" />
98+
</>
99+
),
100+
itemComponent: ({ item, onSelect }) => (
101+
<div onClick={onSelect}>
102+
{(item as FashionHit).name}
103+
</div>
104+
),
105+
},
106+
{
107+
feedID: 'Amazon',
108+
headerComponent: () => (
109+
<>
110+
<span className="ais-AutocompleteIndexHeaderTitle">
111+
Amazon
112+
</span>
113+
<span className="ais-AutocompleteIndexHeaderLine" />
114+
</>
115+
),
116+
itemComponent: ({ item, onSelect }) => (
117+
<div onClick={onSelect}>
118+
{(item as AmazonHit).product_title}
119+
</div>
120+
),
121+
},
122+
]}
123+
showRecent={{
124+
headerComponent: () => (
125+
<>
126+
<span className="ais-AutocompleteIndexHeaderTitle">
127+
Recent Searches
128+
</span>
129+
<span className="ais-AutocompleteIndexHeaderLine" />
130+
</>
131+
),
132+
}}
133+
/>
134+
135+
<Hits hitComponent={HitComponent} />
136+
137+
<div className="pagination">
138+
<Pagination />
139+
</div>
140+
</div>
141+
</div>
142+
</div>
143+
</main>
144+
</InstantSearch>
145+
</div>
146+
</div>
147+
);
148+
}
149+
150+
function HitComponent({ hit }: { hit: ProductHit }) {
151+
return (
152+
<article>
153+
<h1>
154+
<Highlight attribute="title" hit={hit} />
155+
</h1>
156+
<p>{hit.author?.join(', ')}</p>
157+
</article>
158+
);
159+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# React InstantSearch — Autocomplete multifeed
2+
3+
Showcases `EXPERIMENTAL_Autocomplete` in **feeds-mode**: one composition request
4+
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 `App.tsx` with your own composition.
12+
13+
## Run
14+
15+
From the repo root:
16+
17+
```sh
18+
yarn workspace example-react-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: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
<script></script>
11+
<title>React InstantSearch - Autocomplete multifeed</title>
12+
</head>
13+
14+
<body>
15+
<noscript> You need to enable JavaScript to run this app. </noscript>
16+
<div id="root"></div>
17+
<script type="module" src="index.tsx"></script>
18+
</body>
19+
</html>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react';
2+
import { createRoot } from 'react-dom/client';
3+
4+
import { App } from './App';
5+
6+
createRoot(document.getElementById('root')!).render(<App />);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "example-react-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/react/autocomplete-multifeed --base /examples/react/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+
"react": "19.0.0",
19+
"react-dom": "19.0.0",
20+
"react-instantsearch": "7.29.0",
21+
"react-instantsearch-core": "7.29.0"
22+
},
23+
"devDependencies": {
24+
"@types/react": "19.0.3",
25+
"@vitejs/plugin-react": "4.2.1",
26+
"typescript": "5.5.2",
27+
"vite": "5.0.7",
28+
"vite-plugin-commonjs": "0.10.0"
29+
}
30+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import react from '@vitejs/plugin-react';
2+
import { defineConfig } from 'vite';
3+
import commonjs from 'vite-plugin-commonjs';
4+
5+
export default defineConfig({
6+
plugins: [commonjs(), react()],
7+
build: {
8+
commonjsOptions: {
9+
requireReturnsDefault: 'preferred',
10+
},
11+
},
12+
});

tsconfig.v4.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"examples/react/react-native",
1313
// @algolia/composition is not compatible with algoliasearch v4.
1414
"examples/js/autocomplete-multifeed",
15+
"examples/react/autocomplete-multifeed",
1516
"examples/js/e-commerce-umd/public/packages",
1617
"packages/create-instantsearch-app/src/templates/**/*",
1718
"packages/algolia-experiences"

0 commit comments

Comments
 (0)