Algolia
This article guides you through adding Algolia Search to Docusaurus v3
, assuming you already have an active Algolia account.
Default
Add the following Algolia search configuration:
https://mkeithx.pages.dev
docusaurus.config.js
module.exports = {
...
algolia: {
apiKey: 'YOUR_API_KEY',
indexName: 'YOUR_INDEX_NAME',
appId: 'YOUR_APP_ID',
},
...
};
Custom
In this method, we will extend Algolia search React component by utilizing the Swizzle method:
Add the following on your site configuration:
https://mkeithx.pages.dev
docusaurus.config.ts
import type { Config } from "@docusaurus/types";
import type * as Preset from "@docusaurus/preset-classic";
const config: Config = {
title: "My Site",
favicon: "img/favicon.ico",
scripts: [
{
src: "https://YOUR_APP_ID-dsn.algolia.net",
rel: "preconnect",
crossorigin: true,
},
],
/* Your site config here */
};
export default config;
JavaScript
- npm
- Yarn
- pnpm
npm run swizzle @docusaurus/theme-classic SearchBar
yarn swizzle @docusaurus/theme-classic SearchBar
pnpm run swizzle @docusaurus/theme-classic SearchBar
Typescript
- npm
- Yarn
- pnpm
npm run swizzle @docusaurus/theme-classic SearchBar --typescript
yarn swizzle @docusaurus/theme-classic SearchBar --typescript
pnpm run swizzle @docusaurus/theme-classic SearchBar --typescript
Choose the --wrap
option and add the following configuration in your src/theme/SearchBar
:
https://mkeithx.pages.dev
- JavaScript
- TypeScript
src/theme/SearchBar.js
import React from "react";
import SearchBar from "@theme-original/SearchBar";
import type SearchBarType from "@theme/SearchBar";
import type { WrapperProps } from "@docusaurus/types";
import { DocSearch } from "@docsearch/react";
export default function SearchBarWrapper(props) {
return (
<div>
<DocSearch
appId="YOUR_APP_ID"
indexName="YOUR_INDEX_NAME"
apiKey="YOUR_API_KEY"
/>
</div>
);
}
src/theme/SearchBar.tsx
import React from "react";
import SearchBar from "@theme-original/SearchBar";
import type SearchBarType from "@theme/SearchBar";
import type { WrapperProps } from "@docusaurus/types";
import { DocSearch } from "@docsearch/react";
type Props = WrapperProps<typeof SearchBarType>;
export default function SearchBarWrapper(props: Props): JSX.Element {
return (
<>
<DocSearch
appId="YOUR_APP_ID"
indexName="YOUR_INDEX_NAME"
apiKey="YOUR_API_KEY"
/>
<SearchBar {...props} />
</>
);
}
tip
Visit documentation to learn more.
Crawlers
Docusaurus highly recommends to use the official v3 crawler configuration.
Crawlers template
- Default
- Custom
new Crawler({
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_API_KEY',
rateLimit: 8,
maxDepth: 10,
startUrls: ['https://YOUR_WEBSITE_URL/'],
sitemaps: ['https://YOUR_WEBSITE_URL/sitemap.xml'],
ignoreCanonicalTo: true,
discoveryPatterns: ['https://YOUR_WEBSITE_URL/**'],
actions: [
{
indexName: 'YOUR_INDEX_NAME',
pathsToMatch: ['https://YOUR_WEBSITE_URL/**'],
recordExtractor: ({ $, helpers }) => {
// priority order: deepest active sub list header -> navbar active item -> 'Documentation'
const lvl0 =
$(
'.menu__link.menu__link--sublist.menu__link--active, .navbar__item.navbar__link--active'
)
.last()
.text() || 'Documentation';
return helpers.docsearch({
recordProps: {
lvl0: {
selectors: '',
defaultValue: lvl0,
},
lvl1: ['header h1', 'article h1'],
lvl2: 'article h2',
lvl3: 'article h3',
lvl4: 'article h4',
lvl5: 'article h5, article td:first-child',
lvl6: 'article h6',
content: 'article p, article li, article td:last-child',
},
indexHeadings: true,
aggregateContent: true,
recordVersion: 'v3',
});
},
},
],
initialIndexSettings: {
YOUR_INDEX_NAME: {
attributesForFaceting: [
'type',
'lang',
'language',
'version',
'docusaurus_tag',
],
attributesToRetrieve: [
'hierarchy',
'content',
'anchor',
'url',
'url_without_anchor',
'type',
],
attributesToHighlight: ['hierarchy', 'content'],
attributesToSnippet: ['content:10'],
camelCaseAttributes: ['hierarchy', 'content'],
searchableAttributes: [
'unordered(hierarchy.lvl0)',
'unordered(hierarchy.lvl1)',
'unordered(hierarchy.lvl2)',
'unordered(hierarchy.lvl3)',
'unordered(hierarchy.lvl4)',
'unordered(hierarchy.lvl5)',
'unordered(hierarchy.lvl6)',
'content',
],
distinct: true,
attributeForDistinct: 'url',
customRanking: [
'desc(weight.pageRank)',
'desc(weight.level)',
'asc(weight.position)',
],
ranking: [
'words',
'filters',
'typo',
'attribute',
'proximity',
'exact',
'custom',
],
highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
highlightPostTag: '</span>',
minWordSizefor1Typo: 3,
minWordSizefor2Typos: 7,
allowTyposOnNumericTokens: false,
minProximity: 1,
ignorePlurals: true,
advancedSyntax: true,
attributeCriteriaComputedByMinProximity: true,
removeWordsIfNoResults: 'allOptional',
separatorsToIndex: '_',
},
},
});
new Crawler({
appId: "<YOUR-APP-ID>",
apiKey: "<YOU-API-KEY>",
rateLimit: 8,
maxDepth: 10,
maxUrls: 5000,
renderJavaScript: false,
startUrls: ["https://YOUR_WEBSITE_URL"],
sitemaps: ["https://YOUR_WEBSITE_URL/sitemap.xml"],
ignoreCanonicalTo: true,
discoveryPatterns: ["https://YOUR_WEBSITE_URL/**"],
# Optional
// highlight-start
exclusionPatterns: [
"https://YOUR_WEBSITE_URL/FOO",
"https://YOUR_WEBSITE_URL/BAR",
],
// highlight-end
schedule: "every 2 day at 6:00 am",
actions: [
{
indexName: "<YOUR_INDEX_NAME>",
pathsToMatch: ["https://YOUR_WEBSITE_URL/**"],
recordExtractor: ({ $, helpers }) => {
// priority order: deepest active sub list header -> navbar active item -> 'Documentation'
const lvl0 =
$(
".menu__link.menu__link--sublist.menu__link--active, .navbar__item.navbar__link--active",
)
.last()
.text() || "Documentation";
return helpers.docsearch({
recordProps: {
lvl0: {
selectors: "",
defaultValue: lvl0,
},
lvl1: ["header h1", "article h1"],
lvl2: "article h2",
lvl3: "article h3",
lvl4: "article h4",
lvl5: "article h5, article td:first-child",
lvl6: "article h6",
content: "article p, article li, article td:last-child",
},
indexHeadings: true,
aggregateContent: true,
recordVersion: "v3",
});
},
},
],
safetyChecks: { beforeIndexPublishing: { maxLostRecordsPercentage: 30 } },
initialIndexSettings: {
YOUR_INDEX_NAME: {
attributesForFaceting: ["type", "lang"],
attributesToRetrieve: [
"hierarchy",
"content",
"anchor",
"url",
"url_without_anchor",
"type",
],
attributesToHighlight: ["hierarchy", "content"],
attributesToSnippet: ["content:10"],
camelCaseAttributes: ["hierarchy", "content"],
searchableAttributes: [
"unordered(hierarchy.lvl0)",
"unordered(hierarchy.lvl1)",
"unordered(hierarchy.lvl2)",
"unordered(hierarchy.lvl3)",
"unordered(hierarchy.lvl4)",
"unordered(hierarchy.lvl5)",
"unordered(hierarchy.lvl6)",
"content",
],
distinct: true,
attributeForDistinct: "url",
customRanking: [
"desc(weight.pageRank)",
"desc(weight.level)",
"asc(weight.position)",
],
ranking: [
"words",
"filters",
"typo",
"attribute",
"proximity",
"exact",
"custom",
],
highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
highlightPostTag: "</span>",
minWordSizefor1Typo: 3,
minWordSizefor2Typos: 7,
allowTyposOnNumericTokens: false,
minProximity: 1,
ignorePlurals: true,
advancedSyntax: true,
attributeCriteriaComputedByMinProximity: true,
removeWordsIfNoResults: "allOptional",
separatorsToIndex: "_",
},
},
});