feat(docs): sidebar item key attribute - fix docs translations key conflicts (#11228)

This commit is contained in:
Sébastien Lorber 2025-07-03 13:40:00 +02:00 committed by GitHub
parent d9d7e855c2
commit da08536816
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 632 additions and 59 deletions

View file

@ -0,0 +1,8 @@
{
"label": "Conflicts",
"link": {
"type": "generated-index",
"title": "Conflicts",
"description": "Testing what happens when docs use similar names"
}
}

View file

@ -0,0 +1,8 @@
{
"label": "Category Index name conflict",
"link": {
"type": "generated-index",
"title": "Category Index name conflict",
"description": "Testing what happens when 2 category index have the same name"
}
}

View file

@ -0,0 +1,6 @@
{
"label": "Alpha",
"link": {
"type": "generated-index"
}
}

View file

@ -0,0 +1,9 @@
{
"key": "CategoryLabelTest alpha",
"label": "CategoryLabelTest",
"link": {
"type": "generated-index",
"title": "test category in Alpha",
"description": "Test description in Alpha"
}
}

View file

@ -0,0 +1,4 @@
---
---
## Test file

View file

@ -0,0 +1,6 @@
{
"label": "Beta",
"link": {
"type": "generated-index"
}
}

View file

@ -0,0 +1,9 @@
{
"key": "CategoryLabelTest beta",
"label": "CategoryLabelTest",
"link": {
"type": "generated-index",
"title": "test category in Beta",
"description": "Test description in Beta"
}
}

View file

@ -0,0 +1,4 @@
---
---
## Test file

View file

@ -0,0 +1,7 @@
---
sidebar_label: Doc sidebar label
---
# Doc 1
Doc 1

View file

@ -0,0 +1,7 @@
---
sidebar_label: Doc sidebar label
---
# Doc 2
Doc 2

View file

@ -8,6 +8,7 @@
/**
* @typedef {import('@docusaurus/plugin-content-docs').SidebarsConfig} SidebarsConfig
* @typedef {import('@docusaurus/plugin-content-docs/lib/sidebars/types').SidebarItemConfig} SidebarItemConfig
* @typedef {import('@docusaurus/plugin-content-docs/lib/sidebars/types').SidebarItemCategoryConfig} SidebarItemCategoryConfig
*/
/** @type {SidebarsConfig} */
@ -63,7 +64,8 @@ const sidebars = {
items: [
{
type: 'link',
label: 'Link ',
label: 'Link',
key: 'link-key-1',
href: 'https://docusaurus.io',
},
],
@ -76,6 +78,7 @@ const sidebars = {
{
type: 'link',
label: 'Link ',
key: 'link-key-2',
href: 'https://docusaurus.io',
},
],
@ -182,14 +185,16 @@ function generateHugeSidebarItems() {
/**
* @param {number} maxLevel
* @param {number} currentLevel
* @param {string} parentKey
* @returns {SidebarItemConfig[]}
*/
function generateRecursive(maxLevel, currentLevel = 0) {
function generateRecursive(maxLevel, currentLevel = 0, parentKey = 'ROOT') {
if (currentLevel === maxLevel) {
return [
{
type: 'link',
href: '/',
key: `link-${parentKey}-maxLevel`,
label: `Link (level ${currentLevel + 1})`,
},
];
@ -198,14 +203,23 @@ function generateHugeSidebarItems() {
const linkItems = Array.from(Array(linksCount).keys()).map((index) => ({
type: 'link',
href: '/',
key: `link-${parentKey}-${index}`,
label: `Link ${index} (level ${currentLevel + 1})`,
}));
const categoryItems = Array.from(Array(categoriesCount).keys()).map(
/**
* @returns {SidebarItemCategoryConfig}
*/
(index) => ({
type: 'category',
label: `Category ${index} (level ${currentLevel + 1})`,
items: generateRecursive(maxLevel, currentLevel + 1),
key: `category-${parentKey}-${index}`,
items: generateRecursive(
maxLevel,
currentLevel + 1,
`${parentKey}-${index}`,
),
}),
);

View file

@ -6,8 +6,8 @@ slug: /sidebar
Creating a sidebar is useful to:
- Group multiple **related documents**
- **Display a sidebar** on each of those documents
- Group multiple **related documents** into an ordered tree
- **Display a common sidebar** on each of those documents
- Provide **paginated navigation**, with next/previous button
To use sidebars on your Docusaurus site:
@ -160,6 +160,20 @@ export default {
};
```
## Passing CSS classes {#passing-css-classes}
To pass CSS classes to a sidebar item, add the optional `className` attribute to any of the items. This is useful to apply visual customizations to specific sidebar items.
```js
{
type: 'doc',
id: 'doc1',
// highlight-start
className: 'sidebar-item--highlighted',
// highlight-end
};
```
## Passing custom props {#passing-custom-props}
To pass in custom props to a sidebar item, add the optional `customProps` object to any of the items. This is useful to apply site customizations by swizzling React components rendering sidebar items.
@ -177,6 +191,28 @@ To pass in custom props to a sidebar item, add the optional `customProps` object
};
```
## Passing a unique key {#passing-custom-props}
Passing a unique `key` attribute can help uniquely identify a sidebar item. Sometimes other attributes (such as `label`) are not enough to distinguish two sidebar items from each other.
```js
{
type: 'category',
// highlight-start
label: 'API', // You may have multiple categories with this widespread label
key: 'api-for-feature-1', // and now, they can be uniquely identified
// highlight-end
};
```
:::info How is this useful?
Docusaurus only uses the `key` attribute to generate unique i18n translation keys. When a translation key conflict happens ([issue](https://github.com/facebook/docusaurus/issues/10913)), Docusaurus will tell you to apply a `key` to distinguish sidebar items.
Alternatively, you may have your own reasons for using the `key` attribute that will be passed to the respective sidebar item React components.
:::
## Sidebar Breadcrumbs {#sidebar-breadcrumbs}
By default, breadcrumbs are rendered at the top, using the "sidebar path" of the current page.

View file

@ -11,14 +11,14 @@ import TabItem from '@theme/TabItem';
import BrowserWindow from '@site/src/components/BrowserWindow';
```
We have introduced three types of item types in the example in the previous section: `doc`, `category`, and `link`, whose usages are fairly intuitive. We will formally introduce their APIs. There's also a fourth type: `autogenerated`, which we will explain in detail later.
The sidebar supports various item types:
- **[Doc](#sidebar-item-doc)**: link to a doc page, associating it with the sidebar
- **[Link](#sidebar-item-link)**: link to any internal or external page
- **[Category](#sidebar-item-category)**: creates a dropdown of sidebar items
- **[Autogenerated](autogenerated.mdx)**: generate a sidebar slice automatically
- **[HTML](#sidebar-item-html)**: renders pure HTML in the item's position
- **[\*Ref](multiple-sidebars.mdx#sidebar-item-ref)**: link to a doc page, without making the item take part in navigation generation
- **[Ref](multiple-sidebars.mdx#sidebar-item-ref)**: link to a doc page, without making the item take part in navigation generation
## Doc: link to a doc {#sidebar-item-doc}
@ -31,6 +31,7 @@ type SidebarItemDoc =
type: 'doc';
id: string;
label: string; // Sidebar label text
key?: string; // Sidebar key to uniquely identify the item
className?: string; // Class name for sidebar label
customProps?: Record<string, unknown>; // Custom props
}
@ -84,8 +85,10 @@ type SidebarItemLink = {
type: 'link';
label: string;
href: string;
className?: string;
description?: string;
key?: string;
className?: string;
customProps?: Record<string, unknown>;
};
```
@ -126,7 +129,9 @@ type SidebarItemHtml = {
type: 'html';
value: string;
defaultStyle?: boolean; // Use default menu item styles
key?: string;
className?: string;
customProps?: Record<string, unknown>;
};
```
@ -173,8 +178,10 @@ type SidebarItemCategory = {
type: 'category';
label: string; // Sidebar label text.
items: SidebarItem[]; // Array of sidebar items.
className?: string;
description?: string;
key?: string;
className?: string;
customProps?: Record<string, unknown>;
// Category options:
collapsible: boolean; // Set the category to be collapsible