1
0
Fork 0

feat(composable-api): Document Composable API (#2793)

This commit is contained in:
Paul Jankowski 2025-11-04 09:40:05 -05:00 committed by GitHub
parent b91e3099c6
commit e5ae33fe90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 330 additions and 9 deletions

View file

@ -99,7 +99,6 @@ function DocSearch(): JSX.Element {
initialScrollY={window.scrollY}
initialQuery={initialQuery}
isAskAiActive={isAskAiActive}
canHandleAskAi={true}
onClose={closeModal}
onAskAiToggle={toggleAskAi}
/>,

View file

@ -3,9 +3,9 @@ import { DocSearchButton as Button, type DocSearchButtonProps as ButtonProps } f
import type { JSX } from 'react';
import React from 'react';
export type DocSearchButtonProps = Omit<ButtonProps, 'keyboardShortcuts'>;
export type DocSearchButtonProps = Omit<ButtonProps, 'keyboardShortcuts' | 'theme'>;
export function DocSearchButton(props: DocSearchButtonProps): JSX.Element {
export function DocSearchButton({ onClick, ...props }: DocSearchButtonProps): JSX.Element {
const { searchButtonRef, keyboardShortcuts, openModal } = useDocSearch();
return (
@ -13,8 +13,8 @@ export function DocSearchButton(props: DocSearchButtonProps): JSX.Element {
ref={searchButtonRef}
keyboardShortcuts={keyboardShortcuts}
onClick={(evt) => {
if (props.onClick) {
props.onClick(evt);
if (onClick) {
onClick(evt);
}
openModal();
}}

View file

@ -5,7 +5,10 @@ import type { JSX } from 'react';
import React from 'react';
import { createPortal } from 'react-dom';
export type DocSearchModalProps = Omit<ModalProps, 'initialScrollY' | 'isAskAiActive' | 'onAskAiToggle'>;
export type DocSearchModalProps = Omit<
ModalProps,
'initialScrollY' | 'isAskAiActive' | 'keyboardShortcuts' | 'onAskAiToggle' | 'onClose' | 'theme'
>;
export function DocSearchModal(props: DocSearchModalProps): JSX.Element | null {
const { isModalActive, onAskAiToggle, closeModal, isAskAiActive, initialQuery } = useDocSearch();

View file

@ -52,7 +52,6 @@ export type DocSearchModalProps = DocSearchProps & {
onAskAiToggle: (toggle: boolean) => void;
onClose?: () => void;
isAskAiActive?: boolean;
canHandleAskAi?: boolean;
translations?: ModalTranslations;
};

View file

@ -198,6 +198,7 @@ docsearch({
},
// Enables/disables showing suggested questions on Ask AI's new conversation screen
// NOTE: Only available with version >= 4.3
suggestedQuestions: true,
},
// ...
@ -239,6 +240,7 @@ in case you want to use different credentials for askAi
},
// Enables/disables showing suggested questions on Ask AI's new conversation screen
// NOTE: Only available with version >= 4.3
suggestedQuestions: true,
}}
/>

View file

@ -0,0 +1,315 @@
---
title: Composable API
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
:::info
The Composable API is available from version `>= 4.3`
:::
DocSearch has a new Composable API for rendering the DocSearch button and modal. This API was
introduced to help with more explicit control over where and how the components are rendered within a page.
## Introduction
The Composable API was introduced to help give more flexibility on how you render and use DocSearch on your website. With it,
you have more control of where, when and how you want to bundle the components and render them.
With Composable API comes two new NPM packages:
- `@docsearch/core` - Shared core logic for managing different states of DocSearch
- `@docsearch/modal` - The actual components used for the DocSearch Modal
:::warning
Because of the nature of composability, this API is only available within React, and not within the `@docsearch/js` package.
:::
## Getting Started
In order to start using the Composable API, you will need to install the following three packages:
<Tabs
groupId="language"
defaultValue="npm"
values={[
{ label: 'npm', value: 'npm', },
{ label: 'yarn', value: 'yarn', },
{ label: 'pnpm', value: 'pnpm' },
{ label: 'bun', value: 'bun' }
]
}>
<TabItem value="npm">
```bash
npm install @docsearch/core @docsearch/modal @docsearch/css
```
</TabItem>
<TabItem value="yarn">
```bash
yarn add @docsearch/core @docsearch/modal @docsearch/css
```
</TabItem>
<TabItem value="pnpm">
```bash
pnpm add @docsearch/core @docsearch/modal @docsearch/css
```
</TabItem>
<TabItem value="bun">
```bash
bun add @docsearch/core @docsearch/modal @docsearch/css
```
</TabItem>
</Tabs>
> Or using your package manager of choice
## Implementation
The most simple implementation would be as follows:
```tsx
import { DocSearch } from '@docsearch/core';
import { DocSearchButton, DocSearchModal } from '@docsearch/modal';
import '@docsearch/css/style.css';
export function Search() {
return (
<DocSearch>
<DocSearchButton />
<DocSearchModal
indexName="YOUR_INDEX_NAME"
appId="YOUR_APP_ID"
apiKey="YOUR_SEARCH_API_KEY"
/>
</DocSearch>
);
}
```
:::info
The actual components MUST be rendered within the `<DocSearch>` Provider in order for them to communicate with the global state.
:::
This setup is slightly more involved with now rendering three different components:
- `<DocSearch>` is the parent element which controls and shares all state with the child components
- `<DocSearchButton />` is the actual button element that is rendered and triggers the DocSearch Modal to open
- `<DocSearchModal />` is the main modal containing the search form, search results, and Ask AI
### Ask AI
Using Ask AI with the Composable API is quite similar to the normal way of using DocSearch. All that is needed is the `askAi` configuration:
```tsx
import { DocSearch } from '@docsearch/core';
import { DocSearchButton, DocSearchModal } from '@docsearch/modal';
import '@docsearch/css/style.css';
export function Search() {
return (
<DocSearch>
<DocSearchButton />
<DocSearchModal
indexName="YOUR_INDEX_NAME"
appId="YOUR_APP_ID"
apiKey="YOUR_SEARCH_API_KEY"
// With just a simple assistant ID
askAi="YOUR_ALGOLIA_ASSISTANT_ID"
// Or with a more complex configuration
askAi={{
indexName: 'YOUR_MARKDOWN_INDEX', // Optional: use a different index for Ask AI
apiKey: 'YOUR_SEARCH_API_KEY', // Optional: use a different API key for Ask AI
appId: 'YOUR_APP_ID', // Optional: use a different App ID for Ask AI
assistantId: 'YOUR_ALGOLIA_ASSISTANT_ID',
searchParameters: {
facetFilters: ['language:en', 'version:1.0.0'], // Optional: filter Ask AI context
},
}}
/>
</DocSearch>
);
}
```
You can find more information on Ask AI, and it's setup in it's [dedicated docs][2].
### Advanced
```tsx
export default function AdvancedSearch(): JSX.Element {
return (
<DocSearch
keyboardShortcuts={{
'/': false, // Disable opening/closing the DocSearchModal with '/' key
}}
>
<DocSearchButton
translations={{ buttonText: 'Advanced Search' }} // Change the displayed text on the DocSearchButton
/>
<DocSearchModal
indexName="YOUR_INDEX_NAME"
appId="YOUR_APP_ID"
apiKey="YOUR_SEARCH_API_KEY"
askAi={{ // Enable Ask AI
assistantId: 'YOUR_ALGOLIA_ASSISTANT_ID',
searchParameters: {
facetFilters: ['language:en'],
},
}}
portalContainer='#algolia-search' // Custom element that the DocSearchModal will be rendered into
/>
</DocSearch>
);
}
```
### Bundle saving exports
To help aid in trimming initial bundle size, the `@docsearch/modal` package exposes explicit file exports as well:
```ts
import { DocSearchButton } from '@docsearch/modal/button';
import { DocSearchModal } from '@docsearch/modal/modal';
```
Here is a basic example of delaying the loading of the `DocSearchModal` code until the search button is clicked:
```tsx
import { DocSearch } from '@docsearch/core';
import { DocSearchButton } from '@docsearch/modal/button';
import type { DocSearchModal as DocSearchModalType } from '@docsearch/modal/modal';
import { useState } from 'react';
let DocSearchModal: typeof DocSearchModalType | null = null;
async function importDocSearchModalIfNeeded() {
if (DocSearchModal) {
return;
}
const { DocSearchModal: Modal } = await import('@docsearch/modal/modal');
DocSearchModal = Modal;
}
export default function DynamicModal() {
const [modalLoaded, setModalLoaded] = useState(false);
const loadModal = () => {
importDocSearchModalIfNeeded().then(() => {
setModalLoaded(true);
});
};
return (
<DocSearch>
<DocSearchButton onClick={loadModal} />
{modalLoaded && DocSearchModal && (
<DocSearchModal
indexName="YOUR_INDEX_NAME"
appId="YOUR_APP_ID"
apiKey="YOUR_SEARCH_API_KEY"
/>
)}
</DocSearch>
);
}
```
## Components
### `<DocSearch />`
The `<DocSearch />` component from the `@docsearch/core` package is the main state handler for all of DocSearch.
It utilizes [React Context][1] to enable sharing it's state across nested components.
#### Props
```ts
interface DocSearchProps {
// React children to be rendered within the DocSearch Provider
children: Array<JSX.Element | null> | JSX.Element | React.ReactNode | null;
// Theme to be set enabling style changes for `light` or `dark` themes
theme?: 'light' | 'dark';
// Initial starting query for keyword search
initialQuery?: string;
// Manage supported keyboard shortcuts for opening/closing the DocSearch Modal
keyboardShortcuts?: {
'Ctrl/Cmd+K': boolean,
'/': boolean,
};
}
```
### `<DocSearchButton />`
The main DocSearch search button to trigger the DocSearch Modal.
#### Props
```ts
interface DocSearchButtonProps {
// Optional callback for when the button is clicked. The original click event is passed.
onClick?: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
// Translation strings specific to the button.
translations: {
buttonText?: string;
buttonAriaLabel?: string;
};
}
```
### `<DocSearchModal />`
The main keyword search Modal used to search your documentation.
#### Props
```ts
interface DocSearchModalProps {
/**
* Algolia application id used by the search client.
*/
appId: string;
/**
* Public api key with search permissions for the index.
*/
apiKey: string;
/**
* Name of the algolia index to query.
*
* @deprecated `indexName` will be removed in a future version. Please use `indices` property going forward.
*/
indexName?: string;
/**
* List of indices and _optional_ searchParameters to be used for search.
*
* @see {@link https://docsearch.algolia.com/docs/api#indices}
*/
indices?: Array<DocSearchIndex | string>;
/**
* Configuration or assistant id to enable ask ai mode. Pass a string assistant id or a full config object.
*/
askAi?: DocSearchAskAi | string;
// ...
}
```
More property documentation can be found in the [DocSearch API Reference][3] page.
[1]: https://react.dev/reference/react/createContext
[2]: /docs/v4/askai
[3]: /docs/api

View file

@ -11,6 +11,8 @@ DocSearch v4 provides a significant upgrade over previous versions, offering enh
## Installation
> Looking for the Composable API documentation? You can find it [here][17].
DocSearch packages are available on the [npm registry][10].
<Tabs
@ -379,5 +381,6 @@ This helps the browser establish a quick connection with Algolia, enhancing user
[12]: /docs/api
[13]: /docs/required-configuration#introduce-global-information-as-meta-tags
[14]: /docs/record-extractor#indexing-content-for-faceting
[16]: https://www.algolia.com/doc/guides/managing-results/refine-results/filtering/#facetfilters
[15]: https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/
[16]: https://www.algolia.com/doc/guides/managing-results/refine-results/filtering/#facetfilters
[17]: /docs/composable-api

View file

@ -19,7 +19,7 @@ export default {
{
type: 'category',
label: 'DocSearch v4',
items: ['docsearch', 'styling', 'api', 'examples', 'migrating-from-v3'],
items: ['docsearch', 'composable-api', 'styling', 'api', 'examples', 'migrating-from-v3'],
},
{
type: 'category',