1
0
Fork 0
docsearch/packages/website/docs/api.mdx
Paul Jankowski 0267f55453
feat: Modal and AskAI UX tweaks (#2765)
* feat: UX tweaks for Modal

* Prepare new conversation screen to accept suggested questions

* Add conversation history screen

* Reset basic askai config

* Reset askai api url

* Document new translations

* Remove unused CSS

* Add translation for stopped streaming text

* Add rest of translations

* Bump allowed bundle size

* Bump allowed bundle size
2025-09-23 11:44:23 -04:00

797 lines
18 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: API Reference
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'React', value: 'react', }
]
}>
<TabItem value="js">
## `container`
> `type: string | HTMLElement` | **required**
The container for the DocSearch search box. You can either pass a [CSS selector][5] or an [Element][6]. If there are several containers matching the selector, DocSearch picks up the first one.
## `environment`
> `type: typeof window` | `default: window` | **optional**
The environment in which your application is running.
This is useful if youre using DocSearch in a different context than window.
</TabItem>
</Tabs>
## `appId`
> `type: string` | **required**
Your Algolia application ID.
## `apiKey`
> `type: string` | **required**
Your Algolia Search API key.
## `indices`
> `type: Array<string | DocSearchIndex>`
The list of indices and their _optional_ `searchParameters` to be used for keyword search.
[Algolia Search Parameters][7]
:::tip
The ordering matters in the list, as results are ordered based on `indices` order.
:::
> While `indexName` is in deprecation, it is required to pass either `indices` or `indexName`. Not passing either will result in an `Error` being thrown.
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'React', value: 'react', }
]
}>
<TabItem value="js">
```js
docsearch({
// ...
indices: ['YOUR_ALGOLIA_INDEX'],
// ...
});
```
in case you want to use custom `searchParameters` for the index
```js
docsearch({
// ...
indices: [
{
name: 'YOUR_ALGOLIA_INDEX',
searchParameters: {
facetFilters: ['language:en'],
// ...
}
}
],
// ...
});
```
</TabItem>
<TabItem value="react">
```jsx
<DocSearch
// ...
indices={['YOUR_ALGOLIA_INDEX']}
// ...
/>
```
in case you want to use custom `searchParameters` for the index
```jsx
<DocSearch
// ...
indices={[
{
name: 'YOUR_ALGOLIA_INDEX',
searchParameters: {
facetFilters: ['language:en'],
// ...
}
}
]}
// ...
/>
```
</TabItem>
</Tabs>
## `indexName`
> `type: string` | **deprecated**
:::warning[Deprecation warning]
`indexName` is currently being planned for deprecation. The new recommended property to use is `indices`.
:::
Your Algolia index name.
> While `indexName` is in deprecation, it is required to pass either `indices` or `indexName`. Not passing either will result in an `Error` being thrown.
## `placeholder`
> `type: string` | `default: "Search docs"` | **optional**
The placeholder of the input of the DocSearch pop-up modal. Note: If you add a placeholder it will replace the dynamic placeholder based on askAi, It would be better to edit [translations](#translations)
## `askAi`
> `type: AskAiObject` | `string` | **optional**
Your Algolia Assistant ID.
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'React', value: 'react', }
]
}>
<TabItem value="js">
```js
docsearch({
// ...
askAi: 'YOUR_ALGOLIA_ASSISTANT_ID',
// ...
});
```
or if you want to use different credentials for askAi and add search parameters
```js
docsearch({
// ...
askAi: {
indexName: 'ANOTHER_INDEX_NAME',
apiKey: 'ANOTHER_SEARCH_API_KEY',
appId: 'ANOTHER_APP_ID',
assistantId: 'YOUR_ALGOLIA_ASSISTANT_ID',
searchParameters: {
facetFilters: ['language:en'],
},
},
// ...
});
```
</TabItem>
<TabItem value="react">
```jsx
<DocSearch
// ...
askAi="YOUR_ALGOLIA_ASSISTANT_ID"
/>
```
in case you want to use different credentials for askAi
```jsx
<DocSearch
// ...
askAi={{
indexName: 'ANOTHER_INDEX_NAME',
apiKey: 'ANOTHER_SEARCH_API_KEY',
appId: 'ANOTHER_APP_ID',
assistantId: 'YOUR_ALGOLIA_ASSISTANT_ID',
}}
/>
```
</TabItem>
</Tabs>
:::tip
You can use `facetFilters: ['type:content']` to ensure AskAI only uses records where the `type` attribute is `content` (i.e., only records that actually have content). This is useful if your index contains records for navigation, metadata, or other non-content types.
:::
## `searchParameters`
> `type: SearchParameters` | **optional** | **deprecated**
:::warning[Deprecation warning]
`searchParameters` is currently being planned for deprecation. The new recommended property to use is `indices`.
:::
The [Algolia Search Parameters][7].
## `transformItems`
> `type: function` | `default: items => items` | **optional**
Receives the items from the search response, and is called before displaying them. Should return a new array with the same shape as the original array. Useful for mapping over the items to transform, and remove or reorder them.
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'React', value: 'react', }
]
}>
<TabItem value="js">
```js
docsearch({
// ...
transformItems(items) {
return items.map((item) => ({
...item,
content: item.content.toUpperCase(),
}));
},
});
```
</TabItem>
<TabItem value="react">
```jsx
<DocSearch
// ...
transformItems={(items) => {
return items.map((item) => ({
...item,
content: item.content.toUpperCase(),
}));
}}
/>
```
</TabItem>
</Tabs>
## `hitComponent`
> `type: ({ hit, children }) => JSX.Element` | `default: Hit` | **optional**
The component to display each item.
See the [default implementation][8].
## `transformSearchClient`
> `type: function` | `default: DocSearchTransformClient => DocSearchTransformClient` | **optional**
Useful for transforming the [Algolia Search Client][10], for example to [debounce search queries][9]
## `disableUserPersonalization`
> `type: boolean` | `default: false` | **optional**
Disable saving recent searches and favorites to the local storage.
## `initialQuery`
> `type: string` | **optional**
The search input initial query.
## `navigator`
> `type: Navigator` | **optional**
An implementation of [Algolia Autocomplete][1]s Navigator API to redirect the user when opening a link.
Learn more on the [Navigator API][11] documentation.
## `translations`
> `type: Partial<DocSearchTranslations>` | `default: docSearchTranslations` | **optional**
Allow translations of any raw text and aria-labels present in the DocSearch button or modal components.
<details>
<summary>docSearchTranslations</summary>
<div>
```ts
const translations: DocSearchTranslations = {
button: {
buttonText: 'Search',
buttonAriaLabel: 'Search',
},
modal: {
searchBox: {
clearButtonTitle: 'Clear',
clearButtonAriaLabel: 'Clear the query',
closeButtonText: 'Close',
closeButtonAriaLabel: 'Close',
placeholderText: undefined, // fallback: 'Search docs' or 'Search docs or ask AI a question'
placeholderTextAskAi: undefined, // fallback: 'Ask another question...'
placeholderTextAskAiStreaming: 'Answering...',
// can only be one of the following
// https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/enterkeyhint#value
enterKeyHint: 'search',
enterKeyHintAskAi: 'enter',
searchInputLabel: 'Search',
backToKeywordSearchButtonText: 'Back to keyword search',
backToKeywordSearchButtonAriaLabel: 'Back to keyword search',
newConversationPlaceholder: 'Ask a question',
conversationHistoryTitle: 'My conversation history',
startNewConversationText: 'Start a new conversation',
viewConversationHistoryText: 'Conversation history'
},
startScreen: {
recentSearchesTitle: 'Recent',
noRecentSearchesText: 'No recent searches',
saveRecentSearchButtonTitle: 'Save this search',
removeRecentSearchButtonTitle: 'Remove this search from history',
favoriteSearchesTitle: 'Favorite',
removeFavoriteSearchButtonTitle: 'Remove this search from favorites',
recentConversationsTitle: 'Recent conversations',
removeRecentConversationButtonTitle:
'Remove this conversation from history',
},
errorScreen: {
titleText: 'Unable to fetch results',
helpText: 'You might want to check your network connection.',
},
noResultsScreen: {
noResultsText: 'No results found for',
suggestedQueryText: 'Try searching for',
reportMissingResultsText: 'Believe this query should return results?',
reportMissingResultsLinkText: 'Let us know.',
},
resultsScreen: {
askAiPlaceholder: 'Ask AI: ',
noResultsAskAiPlaceholder: 'Didn't find it in the docs? Ask AI to help: ',
},
askAiScreen: {
disclaimerText:
'Answers are generated with AI which can make mistakes. Verify responses.',
relatedSourcesText: 'Related sources',
thinkingText: 'Thinking...',
copyButtonText: 'Copy',
copyButtonCopiedText: 'Copied!',
copyButtonTitle: 'Copy',
likeButtonTitle: 'Like',
dislikeButtonTitle: 'Dislike',
thanksForFeedbackText: 'Thanks for your feedback!',
preToolCallText: 'Searching...',
duringToolCallText: 'Searching for ',
afterToolCallText: 'Searched for',
// If provided, these override the default rendering of aggregated tool calls:
aggregatedToolCallNode: undefined, // (queries: string[], onSearchQueryClick: (query: string) => void) => React.ReactNode
aggregatedToolCallText: undefined, // (queries: string[]) => { before?: string; separator?: string; lastSeparator?: string; after?: string }
// Text to show when user has stopped streaming a message
stoppedStreamingText: 'You stopped this response',
},
footer: {
selectText: 'Select',
submitQuestionText: 'Submit question',
selectKeyAriaLabel: 'Enter key',
navigateText: 'Navigate',
navigateUpKeyAriaLabel: 'Arrow up',
navigateDownKeyAriaLabel: 'Arrow down',
closeText: 'Close',
backToSearchText: 'Back to search',
closeKeyAriaLabel: 'Escape key',
poweredByText: 'Powered by',
},
newConversation: {
newConversationTitle: 'How can I help you today?',
newConversationDescription: 'I search through your documentation to help you find setup guides, feature details and troubleshooting tips, fast.'
}
},
};
```
</div>
</details>
## `getMissingResultsUrl`
> `type: ({ query: string }) => string` | **optional**
Function to return the URL of your documentation repository.
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'React', value: 'react', }
]
}>
<TabItem value="js">
```js
docsearch({
// ...
getMissingResultsUrl({ query }) {
return `https://github.com/algolia/docsearch/issues/new?title=${query}`;
},
});
```
</TabItem>
<TabItem value="react">
```jsx
<DocSearch
// ...
getMissingResultsUrl={({ query }) => {
return `https://github.com/algolia/docsearch/issues/new?title=${query}`;
}}
/>
```
</TabItem>
</Tabs>
When provided, an informative message wrapped with your link will be displayed on no results searches. The default text can be changed using the [translations](#translations) property.
<div className="uil-ta-center">
<img
src={useBaseUrl('img/assets/noResultsScreen.png')}
alt="No results screen with informative message"
/>
</div>
## `keyboardShortcuts`
> `type: KeyboardShortcuts` | **optional**
Configuration for keyboard shortcuts that trigger the search modal.
### Default behavior:
- `Ctrl/Cmd+K` - Opens and closes the search modal
- `/` - Opens the search modal (doesn't close)
### Interface:
```typescript
interface KeyboardShortcuts {
'Ctrl/Cmd+K'?: boolean; // default: true
'/'?: boolean; // default: true
}
```
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'React', value: 'react', }
]
}>
<TabItem value="js">
```js
// Default - all shortcuts enabled
docsearch({
// ...
});
// Disable slash shortcut
docsearch({
// ...
keyboardShortcuts: { '/': false }
});
// Disable Ctrl/Cmd+K shortcut (also hides button hint)
docsearch({
// ...
keyboardShortcuts: { 'Ctrl/Cmd+K': false }
});
// Disable all keyboard shortcuts
docsearch({
// ...
keyboardShortcuts: { 'Ctrl/Cmd+K': false, '/': false }
});
```
</TabItem>
<TabItem value="react">
```jsx
{/* Default - all shortcuts enabled */}
<DocSearch
// ...
/>
{/* Disable slash shortcut */}
<DocSearch
// ...
keyboardShortcuts={{ '/': false }}
/>
{/* Disable Ctrl/Cmd+K shortcut (also hides button hint) */}
<DocSearch
// ...
keyboardShortcuts={{ 'Ctrl/Cmd+K': false }}
/>
{/* Disable all keyboard shortcuts */}
<DocSearch
// ...
keyboardShortcuts={{ 'Ctrl/Cmd+K': false, '/': false }}
/>
```
</TabItem>
</Tabs>
:::info Keyboard Shortcut Behavior
- **Ctrl/Cmd+K**: Toggle shortcut that both opens and closes the modal
- **/**: Character shortcut that only opens the modal (prevents interference with search typing)
- **Escape**: Always works to close the modal regardless of configuration
:::
## `resultsFooterComponent`
> `type: ({ state }) => JSX.Element` | **optional**
The component to display below the search results.
You get access to the [current state](https://github.com/algolia/autocomplete/blob/next/packages/autocomplete-core/src/types/AutocompleteState.ts) which allows you to retrieve the number of hits returned, the query etc.
[You can find a working example without JSX in this sandbox](https://codesandbox.io/s/docsearch-v3-resultsfootercomponent-without-jsx-jperd5).
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'React', value: 'react', }
]
}>
<TabItem value="js">
```js
docsearch({
// ...
resultsFooterComponent({ state }) {
return {
// The HTML `tag`
type: 'a',
ref: undefined,
constructor: undefined,
key: state.query,
// Its props
props: {
href: 'https://docsearch.algolia.com/apply',
target: '_blank',
onClick: (event) => {
console.log(event);
},
// Raw text rendered in the HTML element
children: `${state.context.nbHits} hits found!`,
},
__v: null,
};
},
});
```
</TabItem>
<TabItem value="react">
```jsx
<DocSearch
// ...
resultsFooterComponent={({ state }) => {
return <h1>{state.context.nbHits} hits found</h1>;
}}
/>
```
</TabItem>
</Tabs>
## `maxResultsPerGroup`
> `type: number` | **optional**
The maximum number of results to display per search group. Default is 5.
[You can find a working example without JSX in this sandbox](https://codesandbox.io/s/docsearch-v3-maxresultspergroup-without-jsx-ct9m22?file=/src/index.js)
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', }
]
}>
<TabItem value="js">
```js
docsearch({
// ...
maxResultsPerGroup: 7,
});
```
</TabItem>
</Tabs>
## `recentSearchesLimit`
> `type: number` | `default: 7` | **optional**
The maximum number of recent searches that are stored for the user. Default is 7.
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js' },
{ label: 'React', value: 'react' }
]}
>
<TabItem value="js">
```js
docsearch({
// ...
recentSearchesLimit: 12
// ...
});
```
</TabItem>
<TabItem value="react">
```jsx
<DocSearch
// ...
recentSearchesLimit={12}
// ...
/>
```
</TabItem>
</Tabs>
## `recentSearchesWithFavoritesLimit`
> `type: number` | `default: 4` | **optional**
The maximum number of recent searches that are stored when the user has favorited searches. Default is 4.
<Tabs
groupId="language"
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js' },
{ label: 'React', value: 'react' }
]}
>
<TabItem value="js">
```js
docsearch({
// ...
recentSearchesWithFavoritesLimit: 5
// ...
});
```
</TabItem>
<TabItem value="react">
```jsx
<DocSearch
// ...
recentSearchesWithFavoritesLimit={5}
// ...
/>
```
</TabItem>
</Tabs>
## `portalContainer` (React-only)
> `type: Element | DocumentFragment` | `default: document.body` | **optional**
The element where the DocSearch modal will be portaled. Use this when you need the overlay to render in a custom DOM node—for example when working inside a shadow root, a specific layout container, or a modal manager. When omitted, the modal portals to `document.body`.
:::warning
This prop only exists in `@docsearch/react`. If you are using **`@docsearch/js`**, use the [`container`](#container) option instead—the value you pass there is both the **mount point** of the search button *and* the portal target for the modal.
:::
<Tabs
groupId="language"
defaultValue="react"
values={[{ label: 'React', value: 'react' }, { label: 'JavaScript', value: 'js' }]}
>
<TabItem value="react">
```jsx
// assume you have a dedicated modal root in your html
<div id="modal-root" />
const portalEl = document.getElementById('modal-root');
<DocSearch
appId="YOUR_APP_ID"
apiKey="YOUR_SEARCH_API_KEY"
indexName="YOUR_INDEX_NAME"
// render the modal inside #modal-root instead of document.body
portalContainer={portalEl}
/>;
```
</TabItem>
<TabItem value="js">
```js
docsearch({
// the element that will **contain the button** and **host the modal portal**
container: '#modal-root',
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY',
indexName: 'YOUR_INDEX_NAME',
});
```
</TabItem>
</Tabs>
[1]: https://www.algolia.com/doc/ui-libraries/autocomplete/introduction/what-is-autocomplete/
[2]: https://github.com/algolia/docsearch/
[3]: https://github.com/algolia/docsearch/tree/master
[4]: /docs/legacy/dropdown
[5]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors
[6]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
[7]: https://www.algolia.com/doc/api-reference/search-api-parameters/
[8]: https://github.com/algolia/docsearch/blob/main/packages/docsearch-react/src/Hit.tsx
[9]: https://codesandbox.io/s/docsearch-v3-debounced-search-gnx87
[10]: https://www.algolia.com/doc/api-client/getting-started/what-is-the-api-client/javascript/?client=javascript
[11]: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/keyboard-navigation/