mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-21 04:57:05 +02:00
docs: create Docusaurus v2.4.0 release docs + changelog + release blog post (#8811)
This commit is contained in:
parent
da9f86409d
commit
97caab16d4
105 changed files with 19157 additions and 22 deletions
|
@ -0,0 +1,3 @@
|
|||
<span>Hello {props.name}</span>
|
||||
|
||||
This is text some content from `_markdown-partial-example.md`.
|
|
@ -0,0 +1,256 @@
|
|||
---
|
||||
id: admonitions
|
||||
description: Handling admonitions/callouts in Docusaurus Markdown
|
||||
slug: /markdown-features/admonitions
|
||||
---
|
||||
|
||||
# Admonitions
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Admonition from '@theme/Admonition';
|
||||
|
||||
In addition to the basic Markdown syntax, we have a special admonitions syntax by wrapping text with a set of 3 colons, followed by a label denoting its type.
|
||||
|
||||
Example:
|
||||
|
||||
```md
|
||||
:::note
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::danger
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
:::note
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
:::danger
|
||||
|
||||
Some **content** with _Markdown_ `syntax`. Check [this `api`](#).
|
||||
|
||||
:::
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Usage with Prettier {#usage-with-prettier}
|
||||
|
||||
If you use [Prettier](https://prettier.io) to format your Markdown files, Prettier might auto-format your code to invalid admonition syntax. To avoid this problem, add empty lines around the starting and ending directives. This is also why the examples we show here all have empty lines around the content.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```md
|
||||
<!-- Prettier doesn't change this -->
|
||||
:::note
|
||||
|
||||
Hello world
|
||||
|
||||
:::
|
||||
|
||||
<!-- Prettier changes this -->
|
||||
:::note
|
||||
Hello world
|
||||
:::
|
||||
|
||||
<!-- to this -->
|
||||
::: note Hello world:::
|
||||
```
|
||||
|
||||
## Specifying title {#specifying-title}
|
||||
|
||||
You may also specify an optional title.
|
||||
|
||||
```md
|
||||
:::note Your Title
|
||||
|
||||
Some **content** with _Markdown_ `syntax`.
|
||||
|
||||
:::
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
:::note Your Title
|
||||
|
||||
Some **content** with _Markdown_ `syntax`.
|
||||
|
||||
:::
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Admonitions with MDX {#admonitions-with-mdx}
|
||||
|
||||
You can use MDX inside admonitions too!
|
||||
|
||||
```jsx
|
||||
import Tabs from '@theme/Tabs';
|
||||
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
:::tip Use tabs in admonitions
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="apple" label="Apple">This is an apple 🍎</TabItem>
|
||||
<TabItem value="orange" label="Orange">This is an orange 🍊</TabItem>
|
||||
<TabItem value="banana" label="Banana">This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
:::tip Use tabs in admonitions
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="apple" label="Apple">This is an apple 🍎</TabItem>
|
||||
<TabItem value="orange" label="Orange">This is an orange 🍊</TabItem>
|
||||
<TabItem value="banana" label="Banana">This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Usage in JSX {#usage-in-jsx}
|
||||
|
||||
Outside of Markdown, you can use the `@theme/Admonition` component to get the same output.
|
||||
|
||||
```jsx title="MyReactPage.jsx"
|
||||
import Admonition from '@theme/Admonition';
|
||||
|
||||
export default function MyReactPage() {
|
||||
return (
|
||||
<div>
|
||||
<Admonition type="info">
|
||||
<p>Some information</p>
|
||||
</Admonition>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The types that are accepted are the same as above: `note`, `tip`, `danger`, `info`, `caution`. Optionally, you can specify an icon by passing a JSX element or a string, or a title:
|
||||
|
||||
```jsx title="MyReactPage.jsx"
|
||||
<Admonition type="tip" icon="💡" title="Did you know...">
|
||||
<p>
|
||||
Use plugins to introduce shorter syntax for the most commonly used JSX
|
||||
elements in your project.
|
||||
</p>
|
||||
</Admonition>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Admonition type="tip" icon="💡" title="Did you know...">
|
||||
<p>
|
||||
Use plugins to introduce shorter syntax for the most commonly used JSX
|
||||
elements in your project.
|
||||
</p>
|
||||
</Admonition>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Customizing admonitions {#customizing-admonitions}
|
||||
|
||||
There are two kinds of customizations possible with admonitions: **parsing** and **rendering**.
|
||||
|
||||
### Customizing rendering behavior {#customizing-rendering-behavior}
|
||||
|
||||
You can customize how each individual admonition type is rendered through [swizzling](../../swizzling.mdx). You can often achieve your goal through a simple wrapper. For example, in the follow example, we swap out the icon for `info` admonitions only.
|
||||
|
||||
```jsx title="src/theme/Admonition.js"
|
||||
import React from 'react';
|
||||
import Admonition from '@theme-original/Admonition';
|
||||
import MyIcon from '@site/static/img/info.svg';
|
||||
|
||||
export default function AdmonitionWrapper(props) {
|
||||
if (props.type !== 'info') {
|
||||
return <Admonition {...props} />;
|
||||
}
|
||||
return <Admonition icon={<MyIcon />} {...props} />;
|
||||
}
|
||||
```
|
||||
|
||||
### Customizing parsing behavior {#customizing-parsing-behavior}
|
||||
|
||||
Admonitions are implemented with a [Remark plugin](./markdown-features-plugins.mdx). The plugin is designed to be configurable. To customize the Remark plugin for a specific content plugin (docs, blog, pages), pass the options through the `admonitions` key.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
admonitions: {
|
||||
tag: ':::',
|
||||
keywords: ['note', 'tip', 'info', 'caution', 'danger'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
The plugin accepts two options:
|
||||
|
||||
- `tag`: The tag that encloses the admonition. Defaults to `:::`.
|
||||
- `keywords`: An array of keywords that can be used as the type for the admonition. Note that if you override this, the default values will not be applied.
|
||||
|
||||
The `keyword` will be passed as the `type` prop of the `Admonition` component. If you register more types than the default, you are also responsible for providing their implementation—including the container's style, icon, default title text, etc. You would usually need to [eject](../../swizzling.mdx#ejecting) the `@theme/Admonition` component, so you could re-use the same infrastructure as the other types.
|
|
@ -0,0 +1,234 @@
|
|||
---
|
||||
id: assets
|
||||
description: Handling assets in Docusaurus Markdown
|
||||
slug: /markdown-features/assets
|
||||
---
|
||||
|
||||
# Assets
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
Sometimes you want to link to assets (e.g. docx files, images...) directly from Markdown files, and it is convenient to co-locate the asset next to the Markdown file using it.
|
||||
|
||||
Let's imagine the following file structure:
|
||||
|
||||
```
|
||||
# Your doc
|
||||
/website/docs/myFeature.mdx
|
||||
|
||||
# Some assets you want to use
|
||||
/website/docs/assets/docusaurus-asset-example-banner.png
|
||||
/website/docs/assets/docusaurus-asset-example.docx
|
||||
```
|
||||
|
||||
## Images {#images}
|
||||
|
||||
You can display images in three different ways: Markdown syntax, CJS require, or ES imports syntax.
|
||||
|
||||
```mdx-code-block
|
||||
<Tabs>
|
||||
<TabItem value="Markdown syntax">
|
||||
```
|
||||
|
||||
Display images using simple Markdown syntax:
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
<TabItem value="CommonJS require">
|
||||
```
|
||||
|
||||
Display images using inline CommonJS `require` in JSX image tag:
|
||||
|
||||
```jsx
|
||||
<img
|
||||
src={require('./assets/docusaurus-asset-example-banner.png').default}
|
||||
alt="Example banner"
|
||||
/>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
<TabItem value="Import statement">
|
||||
```
|
||||
|
||||
Display images using ES `import` syntax and JSX image tag:
|
||||
|
||||
```jsx
|
||||
import myImageUrl from './assets/docusaurus-asset-example-banner.png';
|
||||
|
||||
<img src={myImageUrl} alt="Example banner" />;
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
All of the above result in displaying the image:
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||

|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
:::note
|
||||
|
||||
If you are using [@docusaurus/plugin-ideal-image](../../api/plugins/plugin-ideal-image.mdx), you need to use the dedicated image component, as documented.
|
||||
|
||||
:::
|
||||
|
||||
## Files {#files}
|
||||
|
||||
In the same way, you can link to existing assets by `require`'ing them and using the returned URL in `video`s, `a` anchor links, etc.
|
||||
|
||||
```md
|
||||
# My Markdown page
|
||||
|
||||
<a target="\_blank" href={require('./assets/docusaurus-asset-example.docx').default}> Download this docx </a>
|
||||
|
||||
or
|
||||
|
||||
[Download this docx using Markdown](./assets/docusaurus-asset-example.docx)
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
<a
|
||||
target="_blank"
|
||||
href={require('../../assets/docusaurus-asset-example.docx').default}>
|
||||
{'Download this docx'}
|
||||
</a>
|
||||
|
||||
[Download this docx using Markdown](../../assets/docusaurus-asset-example.docx)
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
:::info Markdown links are always file paths
|
||||
|
||||
If you use the Markdown image or link syntax, all asset paths will be resolved as file paths by Docusaurus and automatically converted to `require()` calls. You don't need to use `require()` in Markdown unless you use the JSX syntax, which you do have to handle yourself.
|
||||
|
||||
:::
|
||||
|
||||
## Inline SVGs {#inline-svgs}
|
||||
|
||||
Docusaurus supports inlining SVGs out of the box.
|
||||
|
||||
```jsx
|
||||
import DocusaurusSvg from './docusaurus.svg';
|
||||
|
||||
<DocusaurusSvg />;
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
import DocusaurusSvg from '@site/static/img/docusaurus.svg';
|
||||
|
||||
<DocusaurusSvg />
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
This can be useful if you want to alter the part of the SVG image via CSS. For example, you can change one of the SVG colors based on the current theme.
|
||||
|
||||
```jsx
|
||||
import DocusaurusSvg from './docusaurus.svg';
|
||||
|
||||
<DocusaurusSvg className="themedDocusaurus" />;
|
||||
```
|
||||
|
||||
```css
|
||||
[data-theme='light'] .themedDocusaurus [fill='#FFFF50'] {
|
||||
fill: greenyellow;
|
||||
}
|
||||
|
||||
[data-theme='dark'] .themedDocusaurus [fill='#FFFF50'] {
|
||||
fill: seagreen;
|
||||
}
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
<DocusaurusSvg className="themedDocusaurus" />
|
||||
</BrowserWindow>
|
||||
|
||||
## Themed Images {#themed-images}
|
||||
|
||||
Docusaurus supports themed images: the `ThemedImage` component (included in the themes) allows you to switch the image source based on the current theme.
|
||||
|
||||
```jsx
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
|
||||
<ThemedImage
|
||||
alt="Docusaurus themed image"
|
||||
// highlight-start
|
||||
sources={{
|
||||
light: useBaseUrl('/img/docusaurus_light.svg'),
|
||||
dark: useBaseUrl('/img/docusaurus_dark.svg'),
|
||||
}}
|
||||
// highlight-end
|
||||
/>;
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
|
||||
<BrowserWindow>
|
||||
<ThemedImage
|
||||
alt="Docusaurus themed image"
|
||||
sources={{
|
||||
light: useBaseUrl('/img/docusaurus_keytar.svg'),
|
||||
dark: useBaseUrl('/img/docusaurus_speed.svg'),
|
||||
}}
|
||||
/>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
### GitHub-style themed images {#github-style-themed-images}
|
||||
|
||||
GitHub uses its own [image theming approach](https://github.blog/changelog/2021-11-24-specify-theme-context-for-images-in-markdown/) with path fragments, which you can easily implement yourself.
|
||||
|
||||
To toggle the visibility of an image using the path fragment (for GitHub, it's `#gh-dark-mode-only` and `#gh-light-mode-only`), add the following to your custom CSS (you can also use your own suffix if you don't want to be coupled to GitHub):
|
||||
|
||||
```css title="src/css/custom.css"
|
||||
[data-theme='light'] img[src$='#gh-dark-mode-only'],
|
||||
[data-theme='dark'] img[src$='#gh-light-mode-only'] {
|
||||
display: none;
|
||||
}
|
||||
```
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||

|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Static assets {#static-assets}
|
||||
|
||||
If a Markdown link or image has an absolute path, the path will be seen as a file path and will be resolved from the static directories. For example, if you have configured [static directories](../../static-assets.mdx) to be `['public', 'static']`, then for the following image:
|
||||
|
||||
```md title="my-doc.md"
|
||||

|
||||
```
|
||||
|
||||
Docusaurus will try to look for it in both `static/img/docusaurus.png` and `public/img/docusaurus.png`. The link will then be converted to a `require()` call instead of staying as a URL. This is desirable in two regards:
|
||||
|
||||
1. You don't have to worry about the base URL, which Docusaurus will take care of when serving the asset;
|
||||
2. The image enters Webpack's build pipeline and its name will be appended by a hash, which enables browsers to aggressively cache the image and improves your site's performance.
|
||||
|
||||
If you intend to write URLs, you can use the `pathname://` protocol to disable automatic asset linking.
|
||||
|
||||
```md
|
||||

|
||||
```
|
||||
|
||||
This link will be generated as `<img src="/img/docusaurus-asset-example-banner.png" alt="banner" />`, without any processing or file existence checking.
|
|
@ -0,0 +1,848 @@
|
|||
---
|
||||
id: code-blocks
|
||||
description: Handling code blocks in Docusaurus Markdown
|
||||
slug: /markdown-features/code-blocks
|
||||
---
|
||||
|
||||
# Code blocks
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
Code blocks within documentation are super-powered 💪.
|
||||
|
||||
## Code title {#code-title}
|
||||
|
||||
You can add a title to the code block by adding a `title` key after the language (leave a space between them).
|
||||
|
||||
````md
|
||||
```jsx title="/src/components/HelloCodeTitle.js"
|
||||
function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
```
|
||||
|
||||
```jsx title="/src/components/HelloCodeTitle.js"
|
||||
function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Syntax highlighting {#syntax-highlighting}
|
||||
|
||||
Code blocks are text blocks wrapped around by strings of 3 backticks. You may check out [this reference](https://github.com/mdx-js/specification) for the specifications of MDX.
|
||||
|
||||
````md
|
||||
```js
|
||||
console.log('Every repo must come with a mascot.');
|
||||
```
|
||||
````
|
||||
|
||||
Use the matching language meta string for your code block, and Docusaurus will pick up syntax highlighting automatically, powered by [Prism React Renderer](https://github.com/FormidableLabs/prism-react-renderer).
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
```js
|
||||
console.log('Every repo must come with a mascot.');
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
### Theming {#theming}
|
||||
|
||||
By default, the Prism [syntax highlighting theme](https://github.com/FormidableLabs/prism-react-renderer#theming) we use is [Palenight](https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/themes/palenight.js). You can change this to another theme by passing `theme` field in `prism` as `themeConfig` in your docusaurus.config.js.
|
||||
|
||||
For example, if you prefer to use the `dracula` highlighting theme:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
prism: {
|
||||
// highlight-next-line
|
||||
theme: require('prism-react-renderer/themes/dracula'),
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Because a Prism theme is just a JS object, you can also write your own theme if you are not satisfied with the default. Docusaurus enhances the `github` and `vsDark` themes to provide richer highlight, and you can check our implementations for the [light](https://github.com/facebook/docusaurus/blob/main/website/src/utils/prismLight.mjs) and [dark](https://github.com/facebook/docusaurus/blob/main/website/src/utils/prismDark.mjs) code block themes.
|
||||
|
||||
### Supported Languages {#supported-languages}
|
||||
|
||||
By default, Docusaurus comes with a subset of [commonly used languages](https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/vendor/prism/includeLangs.js).
|
||||
|
||||
:::caution
|
||||
|
||||
Some popular languages like Java, C#, or PHP are not enabled by default.
|
||||
|
||||
:::
|
||||
|
||||
To add syntax highlighting for any of the other [Prism-supported languages](https://prismjs.com/#supported-languages), define it in an array of additional languages.
|
||||
|
||||
:::note
|
||||
|
||||
Each additional language has to be a valid Prism component name. For example, Prism would map the _language_ `cs` to `csharp`, but only `prism-csharp.js` exists as a _component_, so you need to use `additionalLanguages: ['csharp']`. You can look into `node_modules/prismjs/components` to find all components (languages) available.
|
||||
|
||||
:::
|
||||
|
||||
For example, if you want to add highlighting for the PowerShell language:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
prism: {
|
||||
// highlight-next-line
|
||||
additionalLanguages: ['powershell'],
|
||||
},
|
||||
// ...
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
After adding `additionalLanguages`, restart Docusaurus.
|
||||
|
||||
If you want to add highlighting for languages not yet supported by Prism, you can swizzle `prism-include-languages`:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic prism-include-languages
|
||||
```
|
||||
|
||||
It will produce `prism-include-languages.js` in your `src/theme` folder. You can add highlighting support for custom languages by editing `prism-include-languages.js`:
|
||||
|
||||
```js title="src/theme/prism-include-languages.js"
|
||||
const prismIncludeLanguages = (Prism) => {
|
||||
// ...
|
||||
|
||||
additionalLanguages.forEach((lang) => {
|
||||
require(`prismjs/components/prism-${lang}`);
|
||||
});
|
||||
|
||||
// highlight-next-line
|
||||
require('/path/to/your/prism-language-definition');
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
You can refer to [Prism's official language definitions](https://github.com/PrismJS/prism/tree/master/components) when you are writing your own language definitions.
|
||||
|
||||
## Line highlighting {#line-highlighting}
|
||||
|
||||
### Highlighting with comments {#highlighting-with-comments}
|
||||
|
||||
You can use comments with `highlight-next-line`, `highlight-start`, and `highlight-end` to select which lines are highlighted.
|
||||
|
||||
````md
|
||||
```js
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
// highlight-next-line
|
||||
return 'This text is highlighted!';
|
||||
}
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
|
||||
function HighlightMoreText(highlight) {
|
||||
// highlight-start
|
||||
if (highlight) {
|
||||
return 'This range is highlighted!';
|
||||
}
|
||||
// highlight-end
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
```
|
||||
|
||||
```js
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
// highlight-next-line
|
||||
return 'This text is highlighted!';
|
||||
}
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
|
||||
function HighlightMoreText(highlight) {
|
||||
// highlight-start
|
||||
if (highlight) {
|
||||
return 'This range is highlighted!';
|
||||
}
|
||||
// highlight-end
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
Supported commenting syntax:
|
||||
|
||||
| Style | Syntax |
|
||||
| ---------- | ------------------------ |
|
||||
| C-style | `/* ... */` and `// ...` |
|
||||
| JSX-style | `{/* ... */}` |
|
||||
| Bash-style | `# ...` |
|
||||
| HTML-style | `<!-- ... -->` |
|
||||
|
||||
We will do our best to infer which set of comment styles to use based on the language, and default to allowing _all_ comment styles. If there's a comment style that is not currently supported, we are open to adding them! Pull requests welcome. Note that different comment styles have no semantic difference, only their content does.
|
||||
|
||||
You can set your own background color for highlighted code line in your `src/css/custom.css` which will better fit to your selected syntax highlighting theme. The color given below works for the default highlighting theme (Palenight), so if you are using another theme, you will have to tweak the color accordingly.
|
||||
|
||||
```css title="/src/css/custom.css"
|
||||
:root {
|
||||
--docusaurus-highlighted-code-line-bg: rgb(72, 77, 91);
|
||||
}
|
||||
|
||||
/* If you have a different syntax highlighting theme for dark mode. */
|
||||
[data-theme='dark'] {
|
||||
/* Color which works with dark mode syntax highlighting theme */
|
||||
--docusaurus-highlighted-code-line-bg: rgb(100, 100, 100);
|
||||
}
|
||||
```
|
||||
|
||||
If you also need to style the highlighted code line in some other way, you can target on `theme-code-block-highlighted-line` CSS class.
|
||||
|
||||
### Highlighting with metadata string {#highlighting-with-metadata-string}
|
||||
|
||||
You can also specify highlighted line ranges within the language meta string (leave a space after the language). To highlight multiple lines, separate the line numbers by commas or use the range syntax to select a chunk of lines. This feature uses the `parse-number-range` library and you can find [more syntax](https://www.npmjs.com/package/parse-numeric-range) on their project details.
|
||||
|
||||
````md
|
||||
```jsx {1,4-6,11}
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
````
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
```
|
||||
|
||||
```jsx {1,4-6,11}
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
:::tip prefer comments
|
||||
|
||||
Prefer highlighting with comments where you can. By inlining highlight in the code, you don't have to manually count the lines if your code block becomes long. If you add/remove lines, you also don't have to offset your line ranges.
|
||||
|
||||
````diff
|
||||
- ```jsx {3}
|
||||
+ ```jsx {4}
|
||||
function HighlightSomeText(highlight) {
|
||||
if (highlight) {
|
||||
+ console.log('Highlighted text found');
|
||||
return 'This text is highlighted!';
|
||||
}
|
||||
|
||||
return 'Nothing highlighted';
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
Below, we will introduce how the magic comment system can be extended to define custom directives and their functionalities. The magic comments would only be parsed if a highlight metastring is not present.
|
||||
|
||||
:::
|
||||
|
||||
### Custom magic comments {#custom-magic-comments}
|
||||
|
||||
`// highlight-next-line` and `// highlight-start` etc. are called "magic comments", because they will be parsed and removed, and their purposes are to add metadata to the next line, or the section that the pair of start- and end-comments enclose.
|
||||
|
||||
You can declare custom magic comments through theme config. For example, you can register another magic comment that adds a `code-block-error-line` class name:
|
||||
|
||||
```mdx-code-block
|
||||
<Tabs>
|
||||
<TabItem value="docusaurus.config.js">
|
||||
```
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
prism: {
|
||||
magicComments: [
|
||||
// Remember to extend the default highlight class name as well!
|
||||
{
|
||||
className: 'theme-code-block-highlighted-line',
|
||||
line: 'highlight-next-line',
|
||||
block: {start: 'highlight-start', end: 'highlight-end'},
|
||||
},
|
||||
// highlight-start
|
||||
{
|
||||
className: 'code-block-error-line',
|
||||
line: 'This will error',
|
||||
},
|
||||
// highlight-end
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
<TabItem value="src/css/custom.css">
|
||||
```
|
||||
|
||||
```css
|
||||
.code-block-error-line {
|
||||
background-color: #ff000020;
|
||||
display: block;
|
||||
margin: 0 calc(-1 * var(--ifm-pre-padding));
|
||||
padding: 0 var(--ifm-pre-padding);
|
||||
border-left: 3px solid #ff000080;
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
<TabItem value="myDoc.md">
|
||||
```
|
||||
|
||||
````md
|
||||
In JavaScript, trying to access properties on `null` will error.
|
||||
|
||||
```js
|
||||
const name = null;
|
||||
// This will error
|
||||
console.log(name.toUpperCase());
|
||||
// Uncaught TypeError: Cannot read properties of null (reading 'toUpperCase')
|
||||
```
|
||||
````
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
```
|
||||
|
||||
In JavaScript, trying to access properties on `null` will error.
|
||||
|
||||
```js
|
||||
const name = null;
|
||||
// This will error
|
||||
console.log(name.toUpperCase());
|
||||
// Uncaught TypeError: Cannot read properties of null (reading 'toUpperCase')
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
If you use number ranges in metastring (the `{1,3-4}` syntax), Docusaurus will apply the **first `magicComments` entry**'s class name. This, by default, is `theme-code-block-highlighted-line`, but if you change the `magicComments` config and use a different entry as the first one, the meaning of the metastring range will change as well.
|
||||
|
||||
You can disable the default line highlighting comments with `magicComments: []`. If there's no magic comment config, but Docusaurus encounters a code block containing a metastring range, it will error because there will be no class name to apply—the highlighting class name, after all, is just a magic comment entry.
|
||||
|
||||
Every magic comment entry will contain three keys: `className` (required), `line`, which applies to the directly next line, or `block` (containing `start` and `end`), which applies to the entire block enclosed by the two comments.
|
||||
|
||||
Using CSS to target the class can already do a lot, but you can unlock the full potential of this feature through [swizzling](../../swizzling.mdx).
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-classic CodeBlock/Line
|
||||
```
|
||||
|
||||
The `Line` component will receive the list of class names, based on which you can conditionally render different markup.
|
||||
|
||||
## Line numbering {#line-numbering}
|
||||
|
||||
You can enable line numbering for your code block by using `showLineNumbers` key within the language meta string (don't forget to add space directly before the key).
|
||||
|
||||
````md
|
||||
```jsx {1,4-6,11} showLineNumbers
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
````
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
```
|
||||
|
||||
```jsx {1,4-6,11} showLineNumbers
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
if (props.isBar) {
|
||||
return <div>Bar</div>;
|
||||
}
|
||||
|
||||
return <div>Foo</div>;
|
||||
}
|
||||
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Interactive code editor {#interactive-code-editor}
|
||||
|
||||
(Powered by [React Live](https://github.com/FormidableLabs/react-live))
|
||||
|
||||
You can create an interactive coding editor with the `@docusaurus/theme-live-codeblock` plugin. First, add the plugin to your package.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/theme-live-codeblock
|
||||
```
|
||||
|
||||
You will also need to add the plugin to your `docusaurus.config.js`.
|
||||
|
||||
```js {3}
|
||||
module.exports = {
|
||||
// ...
|
||||
themes: ['@docusaurus/theme-live-codeblock'],
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
To use the plugin, create a code block with `live` attached to the language meta string.
|
||||
|
||||
````md
|
||||
```jsx live
|
||||
function Clock(props) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
useEffect(() => {
|
||||
const timerID = setInterval(() => tick(), 1000);
|
||||
|
||||
return function cleanup() {
|
||||
clearInterval(timerID);
|
||||
};
|
||||
});
|
||||
|
||||
function tick() {
|
||||
setDate(new Date());
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>It is {date.toLocaleTimeString()}.</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
The code block will be rendered as an interactive editor. Changes to the code will reflect on the result panel live.
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
```
|
||||
|
||||
```jsx live
|
||||
function Clock(props) {
|
||||
const [date, setDate] = useState(new Date());
|
||||
useEffect(() => {
|
||||
const timerID = setInterval(() => tick(), 1000);
|
||||
|
||||
return function cleanup() {
|
||||
clearInterval(timerID);
|
||||
};
|
||||
});
|
||||
|
||||
function tick() {
|
||||
setDate(new Date());
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>It is {date.toLocaleTimeString()}.</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
### Imports {#imports}
|
||||
|
||||
:::caution react-live and imports
|
||||
|
||||
It is not possible to import components directly from the react-live code editor, you have to define available imports upfront.
|
||||
|
||||
:::
|
||||
|
||||
By default, all React imports are available. If you need more imports available, swizzle the react-live scope:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run swizzle @docusaurus/theme-live-codeblock ReactLiveScope -- --eject
|
||||
```
|
||||
|
||||
```jsx title="src/theme/ReactLiveScope/index.js"
|
||||
import React from 'react';
|
||||
|
||||
// highlight-start
|
||||
const ButtonExample = (props) => (
|
||||
<button
|
||||
{...props}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
color: 'black',
|
||||
border: 'solid red',
|
||||
borderRadius: 20,
|
||||
padding: 10,
|
||||
cursor: 'pointer',
|
||||
...props.style,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
// highlight-end
|
||||
|
||||
// Add react-live imports you need here
|
||||
const ReactLiveScope = {
|
||||
React,
|
||||
...React,
|
||||
// highlight-next-line
|
||||
ButtonExample,
|
||||
};
|
||||
|
||||
export default ReactLiveScope;
|
||||
```
|
||||
|
||||
The `ButtonExample` component is now available to use:
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
```
|
||||
|
||||
```jsx live
|
||||
function MyPlayground(props) {
|
||||
return (
|
||||
<div>
|
||||
<ButtonExample onClick={() => alert('hey!')}>Click me</ButtonExample>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
### Imperative Rendering (noInline)
|
||||
|
||||
The `noInline` option should be used to avoid errors when your code spans multiple components or variables.
|
||||
|
||||
````md
|
||||
```jsx live noInline
|
||||
const project = 'Docusaurus';
|
||||
|
||||
const Greeting = () => <p>Hello {project}!</p>;
|
||||
|
||||
render(<Greeting />);
|
||||
```
|
||||
````
|
||||
|
||||
Unlike an ordinary interactive code block, when using `noInline` React Live won't wrap your code in an inline function to render it.
|
||||
|
||||
You will need to explicitly call `render()` at the end of your code to display the output.
|
||||
|
||||
````mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
```jsx live noInline
|
||||
const project = "Docusaurus";
|
||||
|
||||
const Greeting = () => (
|
||||
<p>Hello {project}!</p>
|
||||
);
|
||||
|
||||
render(
|
||||
<Greeting />
|
||||
);
|
||||
```
|
||||
|
||||
</BrowserWindow>
|
||||
````
|
||||
|
||||
## Using JSX markup in code blocks {#using-jsx-markup}
|
||||
|
||||
Code block in Markdown always preserves its content as plain text, meaning you can't do something like:
|
||||
|
||||
```ts
|
||||
type EditUrlFunction = (params: {
|
||||
// This doesn't turn into a link (for good reason!)
|
||||
version: <a href="/docs/versioning">Version</a>;
|
||||
versionDocsDirPath: string;
|
||||
docPath: string;
|
||||
permalink: string;
|
||||
locale: string;
|
||||
}) => string | undefined;
|
||||
```
|
||||
|
||||
If you want to embed HTML markup such as anchor links or bold type, you can use the `<pre>` tag, `<code>` tag, or `<CodeBlock>` component.
|
||||
|
||||
```jsx
|
||||
<pre>
|
||||
<b>Input: </b>1 2 3 4{'\n'}
|
||||
<b>Output: </b>"366300745"{'\n'}
|
||||
</pre>
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
<pre>
|
||||
<b>{'Input: '}</b>
|
||||
{'1 2 3 4\n'}
|
||||
<b>{'Output: '}</b>
|
||||
{'"366300745"\n'}
|
||||
</pre>
|
||||
</BrowserWindow>
|
||||
|
||||
:::caution MDX is whitespace insensitive
|
||||
|
||||
MDX is in line with JSX behavior: line break characters, even when inside `<pre>`, are turned into spaces. You have to explicitly write the new line character for it to be printed out.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
Syntax highlighting only works on plain strings. Docusaurus will not attempt to parse code block content containing JSX children.
|
||||
|
||||
:::
|
||||
|
||||
## Multi-language support code blocks {#multi-language-support-code-blocks}
|
||||
|
||||
With MDX, you can easily create interactive components within your documentation, for example, to display code in multiple programming languages and switch between them using a tabs component.
|
||||
|
||||
Instead of implementing a dedicated component for multi-language support code blocks, we've implemented a general-purpose [`<Tabs>`](./markdown-features-tabs.mdx) component in the classic theme so that you can use it for other non-code scenarios as well.
|
||||
|
||||
The following example is how you can have multi-language code tabs in your docs. Note that the empty lines above and below each language block are **intentional**. This is a [current limitation of MDX](./markdown-features-react.mdx#markdown-and-jsx-interoperability): you have to leave empty lines around Markdown syntax for the MDX parser to know that it's Markdown syntax and not JSX.
|
||||
|
||||
````jsx
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="js" label="JavaScript">
|
||||
|
||||
```js
|
||||
function helloWorld() {
|
||||
console.log('Hello, world!');
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="py" label="Python">
|
||||
|
||||
```py
|
||||
def hello_world():
|
||||
print("Hello, world!")
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="java" label="Java">
|
||||
|
||||
```java
|
||||
class HelloWorld {
|
||||
public static void main(String args[]) {
|
||||
System.out.println("Hello, World");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
````
|
||||
|
||||
And you will get the following:
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs>
|
||||
<TabItem value="js" label="JavaScript">
|
||||
```
|
||||
|
||||
```js
|
||||
function helloWorld() {
|
||||
console.log('Hello, world!');
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
<TabItem value="py" label="Python">
|
||||
```
|
||||
|
||||
```py
|
||||
def hello_world():
|
||||
print("Hello, world!")
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
<TabItem value="java" label="Java">
|
||||
```
|
||||
|
||||
```java
|
||||
class HelloWorld {
|
||||
public static void main(String args[]) {
|
||||
System.out.println("Hello, World");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
If you have multiple of these multi-language code tabs, and you want to sync the selection across the tab instances, refer to the [Syncing tab choices section](markdown-features-tabs.mdx#syncing-tab-choices).
|
||||
|
||||
### Docusaurus npm2yarn remark plugin {#npm2yarn-remark-plugin}
|
||||
|
||||
Displaying CLI commands in both npm and Yarn is a very common need, for example:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @docusaurus/remark-plugin-npm2yarn
|
||||
```
|
||||
|
||||
Docusaurus provides such a utility out of the box, freeing you from using the `Tabs` component every time. To enable this feature, first install the `@docusaurus/remark-plugin-npm2yarn` package as above, and then in `docusaurus.config.js`, for the plugins where you need this feature (doc, blog, pages, etc.), register it in the `remarkPlugins` option. (See [Docs configuration](../../api/plugins/plugin-content-docs.mdx#ex-config) for more details on configuration format)
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-start
|
||||
remarkPlugins: [
|
||||
[require('@docusaurus/remark-plugin-npm2yarn'), {sync: true}],
|
||||
],
|
||||
// highlight-end
|
||||
},
|
||||
pages: {
|
||||
// highlight-next-line
|
||||
remarkPlugins: [require('@docusaurus/remark-plugin-npm2yarn')],
|
||||
},
|
||||
blog: {
|
||||
// highlight-start
|
||||
remarkPlugins: [
|
||||
[
|
||||
require('@docusaurus/remark-plugin-npm2yarn'),
|
||||
{converters: ['pnpm']},
|
||||
],
|
||||
],
|
||||
// highlight-end
|
||||
// ...
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
And then use it by adding the `npm2yarn` key to the code block:
|
||||
|
||||
````md
|
||||
```bash npm2yarn
|
||||
npm install @docusaurus/remark-plugin-npm2yarn
|
||||
```
|
||||
````
|
||||
|
||||
#### Configuration {#npm2yarn-remark-plugin-configuration}
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `sync` | `boolean` | `false` | Whether to sync the selected converter across all code blocks. |
|
||||
| `converters` | `array` | `'yarn'`, `'pnpm'` | The list of converters to use. The order of the converters is important, as the first converter will be used as the default choice. |
|
||||
|
||||
## Usage in JSX {#usage-in-jsx}
|
||||
|
||||
Outside of Markdown, you can use the `@theme/CodeBlock` component to get the same output.
|
||||
|
||||
```jsx
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export default function MyReactPage() {
|
||||
return (
|
||||
<div>
|
||||
{/* highlight-start */}
|
||||
<CodeBlock
|
||||
language="jsx"
|
||||
title="/src/components/HelloCodeTitle.js"
|
||||
showLineNumbers>
|
||||
{`function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}`}
|
||||
</CodeBlock>
|
||||
{/* highlight-end */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<CodeBlock
|
||||
language="jsx"
|
||||
title="/src/components/HelloCodeTitle.js"
|
||||
showLineNumbers>
|
||||
{`function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}`}
|
||||
</CodeBlock>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
The props accepted are `language`, `title` and `showLineNumbers`, in the same way as you write Markdown code blocks.
|
||||
|
||||
Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js" showLineNumbers'`, which is how Markdown code blocks are handled under the hood. However, we recommend you [use comments for highlighting lines](#highlighting-with-comments).
|
||||
|
||||
As [previously stated](#using-jsx-markup), syntax highlighting is only applied when the children is a simple string.
|
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
id: diagrams
|
||||
title: Diagrams
|
||||
description: Writing diagrams with Mermaid
|
||||
slug: /markdown-features/diagrams
|
||||
---
|
||||
|
||||
# Diagrams
|
||||
|
||||
Diagrams can be rendered using [Mermaid](https://mermaid-js.github.io/mermaid/) in a code block.
|
||||
|
||||
## Installation {#installation}
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save @docusaurus/theme-mermaid
|
||||
```
|
||||
|
||||
Enable Mermaid functionality by adding plugin `@docusaurus/theme-mermaid` and setting `markdown.mermaid` to `true` in your `docusaurus.config.js`.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
markdown: {
|
||||
mermaid: true,
|
||||
},
|
||||
themes: ['@docusaurus/theme-mermaid'],
|
||||
};
|
||||
```
|
||||
|
||||
## Usage {#usage}
|
||||
|
||||
Add a code block with language `mermaid`:
|
||||
|
||||
````md title="Example Mermaid diagram"
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
C-->D;
|
||||
```
|
||||
````
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
C-->D;
|
||||
```
|
||||
|
||||
See the [Mermaid syntax documentation](https://mermaid-js.github.io/mermaid/#/./n00b-syntaxReference) for more information on the Mermaid syntax.
|
||||
|
||||
## Theming {#theming}
|
||||
|
||||
The diagram dark and light themes can be changed by setting `mermaid.theme` values in the `themeConfig` in your `docusaurus.config.js`. You can set themes for both light and dark mode.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
mermaid: {
|
||||
theme: {light: 'neutral', dark: 'forest'},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
See the [Mermaid theme documentation](https://mermaid-js.github.io/mermaid/#/theming) for more information on theming Mermaid diagrams.
|
||||
|
||||
## Mermaid Config {#configuration}
|
||||
|
||||
Options in `mermaid.options` will be passed directly to `mermaid.initialize`:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
mermaid: {
|
||||
options: {
|
||||
maxTextSize: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
See the [Mermaid configuration documentation](https://mermaid-js.github.io/mermaid/#/./Setup?id=configuration) for the available config options.
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
id: head-metadata
|
||||
description: Declaring page-specific head metadata through MDX
|
||||
slug: /markdown-features/head-metadata
|
||||
---
|
||||
|
||||
# Head metadata
|
||||
|
||||
## Customizing head metadata {#customizing-head-metadata}
|
||||
|
||||
Docusaurus automatically sets useful page metadata in `<html>`, `<head>` and `<body>` for you. It is possible to add extra metadata (or override existing ones) with the `<head>` tag in Markdown files:
|
||||
|
||||
```md title="markdown-features-head-metadata.mdx"
|
||||
---
|
||||
id: head-metadata
|
||||
title: Head Metadata
|
||||
---
|
||||
|
||||
<!-- highlight-start -->
|
||||
<head>
|
||||
<html className="some-extra-html-class" />
|
||||
<body className="other-extra-body-class" />
|
||||
<title>Head Metadata customized title!</title>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<link rel="canonical" href="https://docusaurus.io/docs/markdown-features/head-metadata" />
|
||||
</head>
|
||||
<!-- highlight-end -->
|
||||
|
||||
# Head Metadata
|
||||
|
||||
My text
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<head>
|
||||
<html className="some-extra-html-class" />
|
||||
<body className="other-extra-body-class" />
|
||||
<title>Head Metadata customized title!</title>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<link rel="canonical" href="https://docusaurus.io/docs/markdown-features/head-metadata" />
|
||||
</head>
|
||||
```
|
||||
|
||||
This `<head>` declaration has been added to the current Markdown doc as a demo. Open your browser DevTools and check how this page's metadata has been affected.
|
||||
|
||||
:::note
|
||||
|
||||
This feature is built on top of the Docusaurus [`<Head>`](./../../docusaurus-core.mdx#head) component. Refer to [react-helmet](https://github.com/nfl/react-helmet) for exhaustive documentation.
|
||||
|
||||
:::
|
||||
|
||||
:::tip You don't need this for regular SEO
|
||||
|
||||
Content plugins (e.g. docs and blog) provide front matter options like `description`, `keywords`, and `image`, which will be automatically applied to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `<head>` tag.
|
||||
|
||||
:::
|
||||
|
||||
## Markdown page description {#markdown-page-description}
|
||||
|
||||
The Markdown pages' description metadata may be used in more places than the head metadata. For example, the docs plugin's [generated category index](../docs/sidebar/items.mdx#generated-index-page) uses the description metadata for the doc cards.
|
||||
|
||||
By default, the description is the first content-ful line, with some efforts to convert it to plain text. For example, the following file...
|
||||
|
||||
```md
|
||||
# Title
|
||||
|
||||
Main content... May contain some [links](./file.mdx) or **emphasis**.
|
||||
```
|
||||
|
||||
...will have the default description "Main content... May contain some links or emphasis". However, **it's not designed to be fully functional**. Where it fails to produce reasonable descriptions, you can explicitly provide one through front matter:
|
||||
|
||||
```md
|
||||
---
|
||||
description: This description will override the default.
|
||||
---
|
||||
|
||||
# Title
|
||||
|
||||
Main content... May contain some [links](./file.mdx) or **emphasis**.
|
||||
```
|
|
@ -0,0 +1,141 @@
|
|||
---
|
||||
id: introduction
|
||||
description: Docusaurus uses MDX. Find out more about Docusaurus-specific features when writing Markdown.
|
||||
slug: /markdown-features
|
||||
---
|
||||
|
||||
# Markdown Features
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
Documentation is one of your product's interfaces with your users. A well-written and well-organized set of docs helps your users understand your product quickly. Our aligned goal here is to help your users find and understand the information they need, as quickly as possible.
|
||||
|
||||
Docusaurus 2 uses modern tooling to help you compose your interactive documentation with ease. You may embed React components, or build live coding blocks where your users may play with the code on the spot. Start sharing your eureka moments with the code your audience cannot walk away from. It is perhaps the most effective way of attracting potential users.
|
||||
|
||||
:::important
|
||||
|
||||
This section assumes you are using the official Docusaurus content plugins.
|
||||
|
||||
:::
|
||||
|
||||
## Standard features {#standard-features}
|
||||
|
||||
Markdown is a syntax that enables you to write formatted content in a readable syntax.
|
||||
|
||||
We use [MDX](https://mdxjs.com/) as the parsing engine, which can do much more than just parsing [standard Markdown syntax](https://daringfireball.net/projects/markdown/syntax), like rendering React components inside your documents as well.
|
||||
|
||||
```md
|
||||
### My Doc Section
|
||||
|
||||
Hello world message with some **bold** text, some _italic_ text, and a [link](/)
|
||||
|
||||

|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
<h3>My Doc Section</h3>
|
||||
|
||||
Hello world message with some **bold** text, some _italic_ text and a [link](/)
|
||||
|
||||

|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Markdown is declarative</summary>
|
||||
|
||||
Some may assume a 1-1 correlation between Markdown and HTML, e.g., `` will always become `<img src="/img/docusaurus.png" alt="Preview" />`, as-is. However, _that is not the case_.
|
||||
|
||||
The Markdown syntax `` only declaratively tells Docusaurus that an image needs to be inserted here, but we may do other things like transforming a [file path to URL path](./markdown-features-assets.mdx#images), so the generated markup may differ from the output of other Markdown renderers, or a naïve hand-transcription to the equivalent JSX/HTML code.
|
||||
|
||||
In general, you should only assume the _semantics_ of the markup (` ``` ` fences become [code blocks](./markdown-features-code-blocks.mdx); `>` becomes [quotes](#quotes), etc.), but not the actual compiled output.
|
||||
|
||||
</details>
|
||||
|
||||
## Front matter {#front-matter}
|
||||
|
||||
Front matter is used to add metadata to your Markdown file. All content plugins have their own front matter schema, and use the front matter to enrich the default metadata inferred from the content or other configuration.
|
||||
|
||||
Front matter is provided at the very top of the file, enclosed by three dashes `---`. The content is parsed as [YAML](https://yaml.org/spec/1.2.2/).
|
||||
|
||||
```md
|
||||
---
|
||||
title: My Doc Title
|
||||
more_data:
|
||||
- Can be provided
|
||||
- as: objects
|
||||
or: arrays
|
||||
---
|
||||
```
|
||||
|
||||
## Quotes {#quotes}
|
||||
|
||||
Markdown quotes are beautifully styled:
|
||||
|
||||
```md
|
||||
> Easy to maintain open source documentation websites.
|
||||
>
|
||||
> — Docusaurus
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
> Easy to maintain open source documentation websites.
|
||||
>
|
||||
> — Docusaurus
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Details {#details}
|
||||
|
||||
Markdown can embed HTML elements, and [`details`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details) HTML elements are beautifully styled:
|
||||
|
||||
```md
|
||||
### Details element example
|
||||
|
||||
<details>
|
||||
<summary>Toggle me!</summary>
|
||||
<div>
|
||||
<div>This is the detailed content</div>
|
||||
<br/>
|
||||
<details>
|
||||
<summary>
|
||||
Nested toggle! Some surprise inside...
|
||||
</summary>
|
||||
<div>😲😲😲😲😲</div>
|
||||
</details>
|
||||
</div>
|
||||
</details>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
<h3>Details element example</h3>
|
||||
|
||||
<details>
|
||||
<summary>Toggle me!</summary>
|
||||
<div>
|
||||
<div>This is the detailed content</div>
|
||||
<br/>
|
||||
<details>
|
||||
<summary>
|
||||
Nested toggle! Some surprise inside...
|
||||
</summary>
|
||||
<div>😲😲😲😲😲</div>
|
||||
</details>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
In practice, those are not really HTML elements, but React JSX elements, which we'll cover next!
|
||||
|
||||
:::
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
id: links
|
||||
description: Links to other pages in Markdown
|
||||
slug: /markdown-features/links
|
||||
---
|
||||
|
||||
# Markdown links
|
||||
|
||||
There are two ways of adding a link to another page: through a **URL path** and a **file path**.
|
||||
|
||||
```md
|
||||
- [URL path to another document](./installation)
|
||||
- [file path to another document](./installation.mdx)
|
||||
```
|
||||
|
||||
URL paths are unprocessed by Docusaurus, and you can see them as directly rendering to `<a href="./installation">`, i.e. it will be resolved according to the page's URL location, rather than its file-system location.
|
||||
|
||||
If you want to reference another Markdown file **included by the same plugin**, you could use the relative path of the document you want to link to. Docusaurus' Markdown loader will convert the file path to the target file's URL path (and hence remove the `.md` extension).
|
||||
|
||||
For example, if you are in `docs/folder/doc1.md` and you want to reference `docs/folder/doc2.md`, `docs/folder/subfolder/doc3.md` and `docs/otherFolder/doc4.md`:
|
||||
|
||||
```md title="docs/folder/doc1.md"
|
||||
I am referencing a [document](doc2.mdx).
|
||||
|
||||
Reference to another [document in a subfolder](subfolder/doc3.mdx).
|
||||
|
||||
[Relative document](../otherFolder/doc4.mdx) referencing works as well.
|
||||
```
|
||||
|
||||
Relative file paths are resolved against the current file's directory. Absolute file paths, on the other hand, are resolved relative to the **content root**, usually `docs/`, `blog/`, or [localized ones](../../i18n/i18n-tutorial.mdx) like `i18n/zh-Hans/plugin-content-docs/current`.
|
||||
|
||||
Absolute file paths can also be relative to the site directory. However, beware that links that begin with `/docs/` or `/blog/` are **not portable** as you would need to manually update them if you create new doc versions or localize them.
|
||||
|
||||
```md
|
||||
You can write [links](/otherFolder/doc4.mdx) relative to the content root (`/docs/`).
|
||||
|
||||
You can also write [links](/docs/otherFolder/doc4.mdx) relative to the site directory, but it's not recommended.
|
||||
```
|
||||
|
||||
Using relative _file_ paths (with `.md` extensions) instead of relative _URL_ links provides the following benefits:
|
||||
|
||||
- Links will keep working on the GitHub interface and many Markdown editors
|
||||
- You can customize the files' slugs without having to update all the links
|
||||
- Moving files around the folders can be tracked by your editor, and some editors may automatically update file links
|
||||
- A [versioned doc](../docs/versioning.mdx) will link to another doc of the exact same version
|
||||
- Relative URL links are very likely to break if you update the [`trailingSlash` config](../../api/docusaurus.config.js.mdx#trailingSlash)
|
||||
|
||||
:::warning
|
||||
|
||||
Markdown file references only work when the source and target files are processed by the same plugin instance. This is a technical limitation of our Markdown processing architecture and will be fixed in the future. If you are linking files between plugins (e.g. linking to a doc page from a blog post), you have to use URL links.
|
||||
|
||||
:::
|
|
@ -0,0 +1,210 @@
|
|||
---
|
||||
id: math-equations
|
||||
description: Writing LaTeX Math Equations
|
||||
slug: /markdown-features/math-equations
|
||||
---
|
||||
|
||||
# Math Equations
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
Mathematical equations can be rendered using [KaTeX](https://katex.org).
|
||||
|
||||
## Usage {#usage}
|
||||
|
||||
Please read [KaTeX](https://katex.org) documentation for more details.
|
||||
|
||||
### Inline {#inline}
|
||||
|
||||
Write inline math equations by wrapping LaTeX equations between `$`:
|
||||
|
||||
```latex
|
||||
Let $f\colon[a,b]\to\R$ be Riemann integrable. Let $F\colon[a,b]\to\R$ be
|
||||
$F(x)=\int_{a}^{x} f(t)\,dt$. Then $F$ is continuous, and at all $x$ such that
|
||||
$f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$.
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
Let $f\colon[a,b] \to \R$ be Riemann integrable. Let $F\colon[a,b]\to\R$ be $F(x)=
|
||||
\int_{a}^{x} f(t)\,dt$. Then $F$ is continuous, and at all $x$ such that $f$ is continuous at $x$, $F$ is differentiable at $x$ with $F'(x)=f(x)$.
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
### Blocks {#blocks}
|
||||
|
||||
For equation block or display mode, use line breaks and `$$`:
|
||||
|
||||
```latex
|
||||
$$
|
||||
I = \int_0^{2\pi} \sin(x)\,dx
|
||||
$$
|
||||
```
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
$$
|
||||
I = \int_0^{2\pi} \sin(x)\,dx
|
||||
$$
|
||||
|
||||
</BrowserWindow>
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
To enable KaTeX, you need to install `remark-math` and `rehype-katex` plugins.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save remark-math@3 rehype-katex@5 hast-util-is-element@1.1.0
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
Use the exact same versions. The latest versions are incompatible with Docusaurus 2.
|
||||
|
||||
:::
|
||||
|
||||
Import the plugins in `docusaurus.config.js`:
|
||||
|
||||
```js
|
||||
const math = require('remark-math');
|
||||
const katex = require('rehype-katex');
|
||||
```
|
||||
|
||||
Add them to your content plugin or preset options (usually `@docusaurus/preset-classic` docs options):
|
||||
|
||||
```js
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
```
|
||||
|
||||
Include the KaTeX CSS in your config under `stylesheets`:
|
||||
|
||||
```js
|
||||
stylesheets: [
|
||||
{
|
||||
href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css',
|
||||
type: 'text/css',
|
||||
integrity:
|
||||
'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM',
|
||||
crossorigin: 'anonymous',
|
||||
},
|
||||
],
|
||||
```
|
||||
|
||||
Overall the changes look like:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-start
|
||||
const math = require('remark-math');
|
||||
const katex = require('rehype-katex');
|
||||
// highlight-end
|
||||
|
||||
module.exports = {
|
||||
title: 'Docusaurus',
|
||||
tagline: 'Build optimized websites quickly, focus on your content',
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
path: 'docs',
|
||||
// highlight-start
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// highlight-start
|
||||
stylesheets: [
|
||||
{
|
||||
href: 'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css',
|
||||
type: 'text/css',
|
||||
integrity:
|
||||
'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM',
|
||||
crossorigin: 'anonymous',
|
||||
},
|
||||
],
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
## Self-hosting KaTeX assets {#self-hosting-katex-assets}
|
||||
|
||||
Loading stylesheets, fonts, and JavaScript libraries from CDN sources is a good practice for popular libraries and assets, since it reduces the amount of assets you have to host. In case you prefer to self-host the `katex.min.css` (along with required KaTeX fonts), you can download the latest version from [KaTeX GitHub releases](https://github.com/KaTeX/KaTeX/releases), extract and copy `katex.min.css` and `fonts` directory (only `.woff2` font types should be enough) to your site's `static` directory, and in `docusaurus.config.js`, replace the stylesheet's `href` from the CDN URL to your local path (say, `/katex/katex.min.css`).
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
stylesheets: [
|
||||
{
|
||||
href: '/katex/katex.min.css',
|
||||
type: 'text/css',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Upgrading rehype-katex beyond recommended version {#upgrading-rehype-katex-beyond-recommended-version}
|
||||
|
||||
:::tip
|
||||
|
||||
Only use the latest version if you actually need the bleeding-edge features of $\KaTeX$. Most users should find the older versions work just as well.
|
||||
|
||||
:::
|
||||
|
||||
The latest versions of `rehype-katex` (starting from `v6.0.0`) has moved to ES Modules, a new module system of JavaScript, which Docusaurus doesn't officially support yet. However, it is possible to import `rehype-katex` dynamically, using an async config creator. Docusaurus will call this creator function and wait for it to return the config object.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
async function createConfig() {
|
||||
// ES Modules are imported with `import()` instead of `require()`, and are imported asynchronously
|
||||
// highlight-next-line
|
||||
const katex = (await import('rehype-katex')).default;
|
||||
return {
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In this case, the overall configuration changes will look like:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-next-line
|
||||
const math = require('remark-math');
|
||||
|
||||
async function createConfig() {
|
||||
// highlight-next-line
|
||||
const katex = (await import('rehype-katex')).default;
|
||||
return {
|
||||
title: 'Docusaurus',
|
||||
tagline: 'Build optimized websites quickly, focus on your content',
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
path: 'docs',
|
||||
// highlight-start
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// highlight-start
|
||||
stylesheets: [
|
||||
{
|
||||
href: 'https://cdn.jsdelivr.net/npm/katex@0.15.2/dist/katex.min.css',
|
||||
type: 'text/css',
|
||||
integrity:
|
||||
'sha384-MlJdn/WNKDGXveldHDdyRP1R4CTHr3FeuDNfhsLPYrq2t0UBkUdK2jyTnXPEK1NQ',
|
||||
crossorigin: 'anonymous',
|
||||
},
|
||||
],
|
||||
// highlight-end
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = createConfig;
|
||||
```
|
|
@ -0,0 +1,215 @@
|
|||
---
|
||||
id: plugins
|
||||
description: Using MDX plugins to expand Docusaurus Markdown functionalities
|
||||
slug: /markdown-features/plugins
|
||||
---
|
||||
|
||||
# MDX Plugins
|
||||
|
||||
Sometimes, you may want to extend or tweak your Markdown syntax. For example:
|
||||
|
||||
- How do I embed youtube videos using the image syntax (``)?
|
||||
- How do I style links that are on their own lines differently, e.g., as a social card?
|
||||
- How do I make every page start with a copyright notice?
|
||||
|
||||
And the answer is: create an MDX plugin! MDX has a built-in [plugin system](https://mdxjs.com/advanced/plugins/) that can be used to customize how the Markdown files will be parsed and transformed to JSX. There are three typical use-cases of MDX plugins:
|
||||
|
||||
- Using existing [remark plugins](https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins) or [rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins);
|
||||
- Creating remark/rehype plugins to transform the elements generated by existing MDX syntax;
|
||||
- Creating remark/rehype plugins to introduce new syntaxes to MDX.
|
||||
|
||||
If you play with the [MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground), you would notice that the MDX transpilation has two intermediate steps: Markdown AST (MDAST), and Hypertext AST (HAST), before arriving at the final JSX output. MDX plugins also come in two forms:
|
||||
|
||||
- **[Remark](https://github.com/remarkjs/remark/)**: processes the Markdown AST.
|
||||
- **[Rehype](https://github.com/rehypejs/rehype/)**: processes the Hypertext AST.
|
||||
|
||||
:::tip
|
||||
|
||||
Use plugins to introduce shorter syntax for the most commonly used JSX elements in your project. The [admonition](./markdown-features-admonitions.mdx) syntax that we offer is also generated by a Remark plugin, and you could do the same for your own use case.
|
||||
|
||||
:::
|
||||
|
||||
## Default plugins {#default-plugins}
|
||||
|
||||
Docusaurus injects [some default Remark plugins](https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-mdx-loader/src/remark) during Markdown processing. These plugins would:
|
||||
|
||||
- Generate the table of contents;
|
||||
- Add anchor links to each heading;
|
||||
- Transform images and links to `require()` calls.
|
||||
- …
|
||||
|
||||
These are all typical use-cases of Remark plugins, which can also be a source of inspiration if you want to implement your own plugin.
|
||||
|
||||
## Installing plugins {#installing-plugins}
|
||||
|
||||
An MDX plugin is usually an npm package, so you install them like other npm packages using npm. Take the [math plugins](./markdown-features-math-equations.mdx) as an example.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save remark-math@3 rehype-katex@4
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
There's recently a trend in the Remark/Rehype ecosystem to migrate to ES Modules, a new JavaScript module system, which Docusaurus doesn't support yet. Please make sure your installed plugin version is CommonJS-compatible before we officially support ESM. Alternatively, you can read about using dynamic `import()` as a workaround in the tutorial of installing [`rehype-katex`](./markdown-features-math-equations.mdx#upgrading-rehype-katex-beyond-recommended-version).
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
<summary>How are <code>remark-math</code> and <code>rehype-katex</code> different?</summary>
|
||||
|
||||
In case you are wondering how Remark and Rehype are different, here is a good example. `remark-math` operates on the Markdown AST, where it sees text like `$...$`, and all it does is transform that to the JSX `<span class="math math-inline">...</span>` without doing too much with the content. This decouples the extraction of math formulae from their rendering, which means you can swap $\KaTeX$ out with other math renderers, like MathJax (with [`rehype-mathjax`](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-mathjax)), just by replacing the Rehype plugin.
|
||||
|
||||
Next, the `rehype-katex` operates on the Hypertext AST where everything has been converted to HTML-like tags already. It traverses all the elements with `math` class and uses $\KaTeX$ to parse and render the content to actual HTML.
|
||||
|
||||
</details>
|
||||
|
||||
Next, add them to the plugin options through plugin or preset config in `docusaurus.config.js`:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-start
|
||||
const math = require('remark-math');
|
||||
const katex = require('rehype-katex');
|
||||
// highlight-end
|
||||
|
||||
module.exports = {
|
||||
title: 'Docusaurus',
|
||||
tagline: 'Build optimized websites quickly, focus on your content',
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-start
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [katex],
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Configuring plugins {#configuring-plugins}
|
||||
|
||||
Some plugins can be configured and accept their own options. In that case, use the `[plugin, pluginOptions]` syntax, like this:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
remarkPlugins: [math],
|
||||
rehypePlugins: [
|
||||
// highlight-next-line
|
||||
[katex, {strict: false}],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
You should check your plugin's documentation for the options it supports.
|
||||
|
||||
## Creating new rehype/remark plugins {#creating-new-rehyperemark-plugins}
|
||||
|
||||
If there isn't an existing package that satisfies your customization need, you can create your own MDX plugin.
|
||||
|
||||
:::note
|
||||
|
||||
The writeup below is **not** meant to be a comprehensive guide to creating a plugin, but just an illustration of how to make it work with Docusaurus. Visit the [Remark](https://github.com/remarkjs/remark/blob/main/doc/plugins.md#creating-plugins) or [Rehype](https://github.com/remarkjs/remark/blob/main/doc/plugins.md#creating-plugins) documentation for a more in-depth explanation of how they work.
|
||||
|
||||
:::
|
||||
|
||||
For example, let's make a plugin that visits every `h2` heading and adds a `Section X. ` prefix. First, create your plugin source file anywhere—you can even publish it as a separate npm package and install it like explained above. We would put ours at `src/remark/section-prefix.js`. A remark/rehype plugin is just a function that receives the `options` and returns a `transformer` that operates on the AST.
|
||||
|
||||
```js "src/remark/section-prefix.js"
|
||||
const visit = require('unist-util-visit');
|
||||
|
||||
const plugin = (options) => {
|
||||
const transformer = async (ast) => {
|
||||
let number = 1;
|
||||
visit(ast, 'heading', (node) => {
|
||||
if (node.depth === 2 && node.children.length > 0) {
|
||||
node.children.unshift({
|
||||
type: 'text',
|
||||
value: `Section ${number}. `,
|
||||
});
|
||||
number++;
|
||||
}
|
||||
});
|
||||
};
|
||||
return transformer;
|
||||
};
|
||||
|
||||
module.exports = plugin;
|
||||
```
|
||||
|
||||
You can now import your plugin in `docusaurus.config.js` and use it just like an installed plugin!
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
// highlight-next-line
|
||||
const sectionPrefix = require('./src/remark/section-prefix');
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-next-line
|
||||
remarkPlugins: [sectionPrefix],
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
The `transformer` has a second parameter [`vfile`](https://github.com/vfile/vfile) which is useful if you need to access the current Markdown file's path.
|
||||
|
||||
```js
|
||||
const plugin = (options) => {
|
||||
const transformer = async (ast, vfile) => {
|
||||
ast.children.unshift({
|
||||
type: 'text',
|
||||
value: `The current file path is ${vfile.path}`,
|
||||
});
|
||||
};
|
||||
return transformer;
|
||||
};
|
||||
```
|
||||
|
||||
Our `transformImage` plugin uses this parameter, for example, to transform relative image references to `require()` calls.
|
||||
|
||||
:::
|
||||
|
||||
:::note
|
||||
|
||||
The default plugins of Docusaurus would operate before the custom remark plugins, and that means the images or links have been converted to JSX with `require()` calls already. For example, in the example above, the table of contents generated is still the same even when all `h2` headings are now prefixed by `Section X.`, because the TOC-generating plugin is called before our custom plugin. If you need to process the MDAST before the default plugins do, use the `beforeDefaultRemarkPlugins` and `beforeDefaultRehypePlugins`.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@docusaurus/preset-classic',
|
||||
{
|
||||
docs: {
|
||||
// highlight-next-line
|
||||
beforeDefaultRemarkPlugins: [sectionPrefix],
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
This would make the table of contents generated contain the `Section X.` prefix as well.
|
||||
|
||||
:::
|
|
@ -0,0 +1,579 @@
|
|||
---
|
||||
id: react
|
||||
description: Using the power of React in Docusaurus Markdown documents, thanks to MDX
|
||||
slug: /markdown-features/react
|
||||
---
|
||||
|
||||
# MDX and React
|
||||
|
||||
```mdx-code-block
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import styles from './markdown-features-react.module.css';
|
||||
```
|
||||
|
||||
## Using JSX in Markdown {#using-jsx-in-markdown}
|
||||
|
||||
Docusaurus has built-in support for [MDX v1](https://mdxjs.com/), which allows you to write JSX within your Markdown files and render them as React components.
|
||||
|
||||
:::note
|
||||
|
||||
While Docusaurus parses both `.md` and `.mdx` files using MDX, some of the syntaxes are treated slightly differently by third-party tools. For the most accurate parsing and better editor support, we recommend using the `.mdx` extension for files containing MDX syntax.
|
||||
|
||||
:::
|
||||
|
||||
Check out the [MDX docs](https://mdxjs.com/) to see what other fancy stuff you can do with MDX.
|
||||
|
||||
### Exporting components {#exporting-components}
|
||||
|
||||
To define any custom component within an MDX file, you have to export it: only paragraphs that start with `export` will be parsed as components instead of prose.
|
||||
|
||||
```jsx
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight> and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
|
||||
|
||||
I can write **Markdown** alongside my _JSX_!
|
||||
```
|
||||
|
||||
Notice how it renders both the markup from your React component and the Markdown syntax:
|
||||
|
||||
```mdx-code-block
|
||||
export const Highlight = ({children, color}) => (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
<BrowserWindow minHeight={240}>
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight>
|
||||
{` `}and <Highlight color="#1877F2">Facebook blue</Highlight> are my favorite colors.
|
||||
|
||||
I can write **Markdown** alongside my _JSX_!
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
:::caution MDX is JSX
|
||||
|
||||
Since all doc files are parsed using MDX, anything that looks like HTML is actually JSX. Therefore, if you need to inline-style a component, follow JSX flavor and provide style objects.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
/* Instead of this: */
|
||||
<span style="background-color: red">Foo</span>
|
||||
/* Use this: */
|
||||
<span style={{backgroundColor: 'red'}}>Foo</span>
|
||||
```
|
||||
|
||||
This behavior is different from Docusaurus 1. See also [Migrating from v1 to v2](../../migration/migration-manual.mdx#convert-style-attributes-to-style-objects-in-mdx).
|
||||
|
||||
In addition, MDX is not [100% compatible with CommonMark](https://github.com/facebook/docusaurus/issues/3018). Use the **[MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground)** to ensure that your syntax is valid MDX.
|
||||
|
||||
:::
|
||||
|
||||
### Importing components {#importing-components}
|
||||
|
||||
You can also import your own components defined in other files or third-party components installed via npm.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```md
|
||||
<!-- Docusaurus theme component -->
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
<!-- External component -->
|
||||
import Button from '@mui/material/Button';
|
||||
<!-- Custom component -->
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
The `@site` alias points to your website's directory, usually where the `docusaurus.config.js` file is. Using an alias instead of relative paths (`'../../src/components/BrowserWindow'`) saves you from updating import paths when moving files around, or when [versioning docs](../docs/versioning.mdx) and [translating](../../i18n/i18n-tutorial.mdx).
|
||||
|
||||
:::
|
||||
|
||||
While declaring components within Markdown is very convenient for simple cases, it becomes hard to maintain because of limited editor support, risks of parsing errors, and low reusability. Use a separate `.js` file when your component involves complex JS logic:
|
||||
|
||||
```jsx title="src/components/Highlight.js"
|
||||
import React from 'react';
|
||||
|
||||
export default function Highlight({children, color}) {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '2px',
|
||||
color: '#fff',
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```md title="markdown-file.mdx"
|
||||
import Highlight from '@site/src/components/Highlight';
|
||||
|
||||
<Highlight color="#25c2a0">Docusaurus green</Highlight>
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
If you use the same component across a lot of files, you don't need to import it everywhere—consider adding it to the global scope. [See below](#mdx-component-scope)
|
||||
|
||||
:::
|
||||
|
||||
### MDX component scope {#mdx-component-scope}
|
||||
|
||||
Apart from [importing a component](#importing-components) and [exporting a component](#exporting-components), a third way to use a component in MDX is to **register it to the global scope**, which will make it automatically available in every MDX file, without any import statements.
|
||||
|
||||
For example, given this MDX file:
|
||||
|
||||
```md
|
||||
- a
|
||||
- list!
|
||||
|
||||
And some <Highlight>custom markup</Highlight>...
|
||||
```
|
||||
|
||||
It will be compiled to a React component containing `ul`, `li`, `p`, and `Highlight` elements. `Highlight` is not a native html element: you need to provide your own React component implementation for it.
|
||||
|
||||
In Docusaurus, the MDX component scope is provided by the `@theme/MDXComponents` file. It's not a React component, _per se_, unlike most other exports under the `@theme/` alias: it is a record from tag names like `Highlight` to their React component implementations.
|
||||
|
||||
If you [swizzle](../../swizzling.mdx) this component, you will find all tags that have been implemented, and you can further customize our implementation by swizzling the respective sub-component, like `@theme/MDXComponents/Code` (which is used to render [Markdown code blocks](./markdown-features-code-blocks.mdx)).
|
||||
|
||||
If you want to register extra tag names (like the `<Highlight>` tag above), you should consider [wrapping `@theme/MDXComponents`](../../swizzling.mdx#wrapping), so you don't have to maintain all the existing mappings. Since the swizzle CLI doesn't allow wrapping non-component files yet, you should manually create the wrapper:
|
||||
|
||||
```js title="src/theme/MDXComponents.js"
|
||||
import React from 'react';
|
||||
// Import the original mapper
|
||||
import MDXComponents from '@theme-original/MDXComponents';
|
||||
// highlight-next-line
|
||||
import Highlight from '@site/src/components/Highlight';
|
||||
|
||||
export default {
|
||||
// Re-use the default mapping
|
||||
...MDXComponents,
|
||||
// Map the "<Highlight>" tag to our Highlight component
|
||||
// `Highlight` will receive all props that were passed to `<Highlight>` in MDX
|
||||
// highlight-next-line
|
||||
Highlight,
|
||||
};
|
||||
```
|
||||
|
||||
And now, you can freely use `<Highlight>` in every page, without writing the import statement:
|
||||
|
||||
```md
|
||||
I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> everywhere!
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
|
||||
I can conveniently use <Highlight color="#25c2a0">Docusaurus green</Highlight> everywhere!
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
:::warning
|
||||
|
||||
We use **upper-case** tag names like `Highlight` on purpose.
|
||||
|
||||
From MDX v2+ onward (Docusaurus v3+), lower-case tag names are always rendered as native html elements, and will not use any component mapping you provide.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
This feature is powered by [a wrapper provider](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/advanced/components#mdxprovider). If you are importing Markdown in a React page, you have to supply this provider yourself through the `MDXContent` theme component.
|
||||
|
||||
```jsx title="src/pages/index.js"
|
||||
import React from 'react';
|
||||
import FeatureDisplay from './_featureDisplay.mdx';
|
||||
// highlight-next-line
|
||||
import MDXContent from '@theme/MDXContent';
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<div>
|
||||
{/* highlight-start */}
|
||||
<MDXContent>
|
||||
<FeatureDisplay />
|
||||
</MDXContent>
|
||||
{/* highlight-end */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
If you don't wrap your imported MDX with `MDXContent`, the global scope will not be available.
|
||||
|
||||
:::
|
||||
|
||||
### Markdown and JSX interoperability {#markdown-and-jsx-interoperability}
|
||||
|
||||
Docusaurus v2 is using MDX v1, which has a lot of known cases where the content fails to be correctly parsed as Markdown. Use the **[MDX playground](https://mdx-git-renovate-babel-monorepo-mdx.vercel.app/playground)** to ensure that your syntax is valid MDX.
|
||||
|
||||
<details>
|
||||
<summary>Samples of parsing failures</summary>
|
||||
|
||||
**A paragraph starting with a JSX tag will be seen entirely as a JSX string:**
|
||||
|
||||
```mdx-code-block
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}>Highlighted text</span> but afterwards _Markdown_ **doesn't work**
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Use JSX for the rest of the line, or prefix the line with some plain text:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>
|
||||
|
||||
​<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}>Use JSX for the paragraph</span> to stop <i>worrying about</i> <b>Markdown</b>
|
||||
|
||||
​<span style={{color: 'red'}}>← This is a zero-width space</span> and afterwards <i>Markdown</i> <b>works</b>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
**Markdown within a JSX tag never works:**
|
||||
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}>**Bold doesn't work**</span>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}>**Bold doesn't work**</span>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Use JSX within JSX tag, or move the Markdown to the outer layer:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red'}}><b>Bold now works</b></span>
|
||||
|
||||
**<span style={{color: 'red'}}>Bold now works</span>**
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<span style={{color: 'red'}}><b>Bold now works</b></span>
|
||||
|
||||
**<span style={{color: 'red'}}>Bold now works</span>**
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
**Text immediately below a JSX tag will be seen as JSX text:**
|
||||
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
**Bold still doesn't work**
|
||||
</div>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<div style={{color: 'red'}}>
|
||||
**Bold still doesn't work**
|
||||
</div>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Add an empty new line:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
**Bold now works**
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
**Bold now works**
|
||||
|
||||
</div>
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
**Markdown text indented by four spaces will be seen as a code block:**
|
||||
|
||||
<Tabs groupId="jsx-and-md">
|
||||
<TabItem value="Problem">
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
You may think I'm just some text...
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
You may think I'm just some text...
|
||||
|
||||
</div>
|
||||
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
<TabItem value="Workaround">
|
||||
|
||||
Don't indent:
|
||||
|
||||
<div className={styles.wrappingBlock}>
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
Now I'm actually just text
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
</div>
|
||||
<div className={styles.wrappingBlock}>
|
||||
<BrowserWindow>
|
||||
<div style={{color: 'red'}}>
|
||||
|
||||
Now I'm actually just text
|
||||
|
||||
</div>
|
||||
</BrowserWindow>
|
||||
</div>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Importing code snippets {#importing-code-snippets}
|
||||
|
||||
You can not only import a file containing a component definition, but also import any code file as raw text, and then insert it in a code block, thanks to [Webpack raw-loader](https://webpack.js.org/loaders/raw-loader/). In order to use `raw-loader`, you first need to install it in your project:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save raw-loader
|
||||
```
|
||||
|
||||
Now you can import code snippets from another file as it is:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
```jsx title="myMarkdownFile.mdx"
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import MyComponentSource from '!!raw-loader!./myComponent';
|
||||
|
||||
<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```mdx-code-block
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import MyComponentSource from '!!raw-loader!@site/src/pages/examples/_myComponent';
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
<CodeBlock language="jsx">{MyComponentSource}</CodeBlock>
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
See [using code blocks in JSX](./markdown-features-code-blocks.mdx#usage-in-jsx) for more details of the `<CodeBlock>` component.
|
||||
|
||||
:::note
|
||||
|
||||
You have to use `<CodeBlock>` rather than the Markdown triple-backtick ` ``` `, because the latter will ship out any of its content as-is, but you want to interpolate the imported text here.
|
||||
|
||||
:::
|
||||
|
||||
:::warning
|
||||
|
||||
This feature is experimental and might be subject to breaking API changes in the future.
|
||||
|
||||
:::
|
||||
|
||||
## Importing Markdown {#importing-markdown}
|
||||
|
||||
You can use Markdown files as components and import them elsewhere, either in Markdown files or in React pages.
|
||||
|
||||
By convention, using the **`_` filename prefix** will not create any doc page and means the Markdown file is a **"partial"**, to be imported by other files.
|
||||
|
||||
```md title="_markdown-partial-example.mdx"
|
||||
<span>Hello {props.name}</span>
|
||||
|
||||
This is text some content from `_markdown-partial-example.mdx`.
|
||||
```
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
```jsx title="someOtherDoc.mdx"
|
||||
import PartialExample from './_markdown-partial-example.mdx';
|
||||
|
||||
<PartialExample name="Sebastien" />
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```mdx-code-block
|
||||
import PartialExample from './_markdown-partial-example.mdx';
|
||||
|
||||
<BrowserWindow>
|
||||
<PartialExample name="Sebastien" />
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
This way, you can reuse content among multiple pages and avoid duplicating materials.
|
||||
|
||||
:::caution
|
||||
|
||||
Currently, the table of contents does not contain the imported Markdown headings. This is a technical limitation that we are trying to solve ([issue](https://github.com/facebook/docusaurus/issues/3915)).
|
||||
|
||||
:::
|
||||
|
||||
## Available exports {#available-exports}
|
||||
|
||||
Within the MDX page, the following variables are available as globals:
|
||||
|
||||
- `frontMatter`: the front matter as a record of string keys and values;
|
||||
- `toc`: the table of contents, as a tree of headings. See also [Inline TOC](./markdown-features-toc.mdx#inline-table-of-contents) for a more concrete use-case.
|
||||
- `contentTitle`: the Markdown title, which is the first `h1` heading in the Markdown text. It's `undefined` if there isn't one (e.g. title specified in the front matter).
|
||||
|
||||
```jsx
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
The table of contents for this page, serialized:
|
||||
|
||||
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
|
||||
|
||||
The front matter of this page:
|
||||
|
||||
<ul>
|
||||
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
|
||||
</ul>
|
||||
|
||||
<p>The title of this page is: <b>{contentTitle}</b></p>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
<BrowserWindow>
|
||||
|
||||
The table of contents for this page, serialized:
|
||||
|
||||
<CodeBlock className="language-json">{JSON.stringify(toc, null, 2)}</CodeBlock>
|
||||
|
||||
The front matter of this page:
|
||||
|
||||
<ul>
|
||||
{Object.entries(frontMatter).map(([key, value]) => <li key={key}><b>{key}</b>: {value}</li>)}
|
||||
</ul>
|
||||
|
||||
<p>The title of this page is: <b>{contentTitle}</b></p>
|
||||
|
||||
</BrowserWindow>
|
||||
```
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.wrappingBlock {
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.wrappingBlock code[class^='codeBlockLines'] {
|
||||
white-space: pre-wrap;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.red[aria-selected='true'] {
|
||||
border-bottom-color: red;
|
||||
}
|
||||
|
||||
.orange {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.orange[aria-selected='true'] {
|
||||
border-bottom-color: orange;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.yellow[aria-selected='true'] {
|
||||
border-bottom-color: yellow;
|
||||
}
|
|
@ -0,0 +1,380 @@
|
|||
---
|
||||
id: tabs
|
||||
description: Using tabs inside Docusaurus Markdown
|
||||
slug: /markdown-features/tabs
|
||||
---
|
||||
|
||||
# Tabs
|
||||
|
||||
```mdx-code-block
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import styles from './markdown-features-tabs-styles.module.css';
|
||||
```
|
||||
|
||||
Docusaurus provides the `<Tabs>` component that you can use in Markdown thanks to [MDX](./markdown-features-react.mdx):
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
```jsx
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="apple" label="Apple" default>
|
||||
This is an apple 🍎
|
||||
</TabItem>
|
||||
<TabItem value="orange" label="Orange">
|
||||
This is an orange 🍊
|
||||
</TabItem>
|
||||
<TabItem value="banana" label="Banana">
|
||||
This is a banana 🍌
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs>
|
||||
<TabItem value="apple" label="Apple">This is an apple 🍎</TabItem>
|
||||
<TabItem value="orange" label="Orange">This is an orange 🍊</TabItem>
|
||||
<TabItem value="banana" label="Banana">This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
It is also possible to provide `values` and `defaultValue` props to `Tabs`:
|
||||
|
||||
```jsx
|
||||
<Tabs
|
||||
defaultValue="apple"
|
||||
values={[
|
||||
{label: 'Apple', value: 'apple'},
|
||||
{label: 'Orange', value: 'orange'},
|
||||
{label: 'Banana', value: 'banana'},
|
||||
]}>
|
||||
<TabItem value="apple">This is an apple 🍎</TabItem>
|
||||
<TabItem value="orange">This is an orange 🍊</TabItem>
|
||||
<TabItem value="banana">This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs
|
||||
defaultValue="apple"
|
||||
values={[
|
||||
{label: 'Apple', value: 'apple'},
|
||||
{label: 'Orange', value: 'orange'},
|
||||
{label: 'Banana', value: 'banana'},
|
||||
]}>
|
||||
<TabItem value="apple">This is an apple 🍎</TabItem>
|
||||
<TabItem value="orange">This is an orange 🍊</TabItem>
|
||||
<TabItem value="banana">This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><code>Tabs</code> props take precedence over the <code>TabItem</code> props:</summary>
|
||||
|
||||
```jsx
|
||||
<Tabs
|
||||
defaultValue="apple"
|
||||
values={[
|
||||
{label: 'Apple 1', value: 'apple'},
|
||||
{label: 'Orange 1', value: 'orange'},
|
||||
{label: 'Banana 1', value: 'banana'},
|
||||
]}>
|
||||
<TabItem value="apple" label="Apple 2">
|
||||
This is an apple 🍎
|
||||
</TabItem>
|
||||
<TabItem value="orange" label="Orange 2">
|
||||
This is an orange 🍊
|
||||
</TabItem>
|
||||
<TabItem value="banana" label="Banana 2" default>
|
||||
This is a banana 🍌
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs
|
||||
defaultValue="apple"
|
||||
values={[
|
||||
{label: 'Apple 1', value: 'apple'},
|
||||
{label: 'Orange 1', value: 'orange'},
|
||||
{label: 'Banana 1', value: 'banana'},
|
||||
]}>
|
||||
<TabItem value="apple" label="Apple 2">This is an apple 🍎</TabItem>
|
||||
<TabItem value="orange" label="Orange 2">This is an orange 🍊</TabItem>
|
||||
<TabItem value="banana" label="Banana 2" default>This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
:::tip
|
||||
|
||||
By default, all tabs are rendered eagerly during the build process, and search engines can index hidden tabs.
|
||||
|
||||
It is possible to only render the default tab with `<Tabs lazy />`.
|
||||
|
||||
:::
|
||||
|
||||
## Displaying a default tab {#displaying-a-default-tab}
|
||||
|
||||
The first tab is displayed by default, and to override this behavior, you can specify a default tab by adding `default` to one of the tab items. You can also set the `defaultValue` prop of the `Tabs` component to the label value of your choice. For example, in the example above, either setting `default` for the `value="apple"` tab or setting `defaultValue="apple"` for the tabs forces the "Apple" tab to be open by default.
|
||||
|
||||
Docusaurus will throw an error if a `defaultValue` is provided for the `Tabs` but it refers to a non-existing value. If you want none of the tabs to be shown by default, use `defaultValue={null}`.
|
||||
|
||||
## Syncing tab choices {#syncing-tab-choices}
|
||||
|
||||
You may want choices of the same kind of tabs to sync with each other. For example, you might want to provide different instructions for users on Windows vs users on macOS, and you want to change all OS-specific instructions tabs in one click. To achieve that, you can give all related tabs the same `groupId` prop. Note that doing this will persist the choice in `localStorage` and all `<Tab>` instances with the same `groupId` will update automatically when the value of one of them is changed. Note that group IDs are globally namespaced.
|
||||
|
||||
```jsx
|
||||
// highlight-next-line
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem>
|
||||
<TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem>
|
||||
</Tabs>
|
||||
|
||||
// highlight-next-line
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem>
|
||||
<TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">Use Ctrl + C to copy.</TabItem>
|
||||
<TabItem value="mac" label="macOS">Use Command + C to copy.</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">Use Ctrl + V to paste.</TabItem>
|
||||
<TabItem value="mac" label="macOS">Use Command + V to paste.</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
For all tab groups that have the same `groupId`, the possible values do not need to be the same. If one tab group is chosen a value that does not exist in another tab group with the same `groupId`, the tab group with the missing value won't change its tab. You can see that from the following example. Try to select Linux, and the above tab groups don't change.
|
||||
|
||||
```jsx
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">
|
||||
I am Windows.
|
||||
</TabItem>
|
||||
<TabItem value="mac" label="macOS">
|
||||
I am macOS.
|
||||
</TabItem>
|
||||
<TabItem value="linux" label="Linux">
|
||||
I am Linux.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">I am Windows.</TabItem>
|
||||
<TabItem value="mac" label="macOS">I am macOS.</TabItem>
|
||||
<TabItem value="linux" label="Linux">I am Linux.</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Tab choices with different group IDs will not interfere with each other:
|
||||
|
||||
```jsx
|
||||
// highlight-next-line
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">Windows in windows.</TabItem>
|
||||
<TabItem value="mac" label="macOS">macOS is macOS.</TabItem>
|
||||
</Tabs>
|
||||
|
||||
// highlight-next-line
|
||||
<Tabs groupId="non-mac-operating-systems">
|
||||
<TabItem value="win" label="Windows">Windows is windows.</TabItem>
|
||||
<TabItem value="unix" label="Unix">Unix is unix.</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs groupId="operating-systems">
|
||||
<TabItem value="win" label="Windows">Windows in windows.</TabItem>
|
||||
<TabItem value="mac" label="macOS">macOS is macOS.</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<Tabs groupId="non-mac-operating-systems">
|
||||
<TabItem value="win" label="Windows">Windows is windows.</TabItem>
|
||||
<TabItem value="unix" label="Unix">Unix is unix.</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Customizing tabs {#customizing-tabs}
|
||||
|
||||
You might want to customize the appearance of a certain set of tabs. You can pass the string in `className` prop, and the specified CSS class will be added to the `Tabs` component:
|
||||
|
||||
```jsx
|
||||
// highlight-next-line
|
||||
<Tabs className="unique-tabs">
|
||||
<TabItem value="Apple">This is an apple 🍎</TabItem>
|
||||
<TabItem value="Orange">This is an orange 🍊</TabItem>
|
||||
<TabItem value="Banana">This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs className="unique-tabs">
|
||||
<TabItem value="Apple">This is an apple 🍎</TabItem>
|
||||
<TabItem value="Orange">This is an orange 🍊</TabItem>
|
||||
<TabItem value="Banana">This is a banana 🍌</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
### Customizing tab headings {#customizing-tab-headings}
|
||||
|
||||
You can also customize each tab heading independently by using the `attributes` field. The extra props can be passed to the headings either through the `values` prop in `Tabs`, or props of each `TabItem`—in the same way as you declare `label`.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
```jsx title="some-doc.mdx"
|
||||
import styles from './styles.module.css';
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="apple" label="Apple" attributes={{className: styles.red}}>
|
||||
This is an apple 🍎
|
||||
</TabItem>
|
||||
<TabItem value="orange" label="Orange" attributes={{className: styles.orange}}>
|
||||
This is an orange 🍊
|
||||
</TabItem>
|
||||
<TabItem value="banana" label="Banana" attributes={{className: styles.yellow}}>
|
||||
This is a banana 🍌
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
```css title="styles.module.css"
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
.red[aria-selected='true'] {
|
||||
border-bottom-color: red;
|
||||
}
|
||||
|
||||
.orange {
|
||||
color: orange;
|
||||
}
|
||||
.orange[aria-selected='true'] {
|
||||
border-bottom-color: orange;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
color: yellow;
|
||||
}
|
||||
.yellow[aria-selected='true'] {
|
||||
border-bottom-color: yellow;
|
||||
}
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs>
|
||||
<TabItem value="apple" label="Apple" attributes={{className: styles.red}}>
|
||||
This is an apple 🍎
|
||||
</TabItem>
|
||||
<TabItem value="orange" label="Orange" attributes={{className: styles.orange}}>
|
||||
This is an orange 🍊
|
||||
</TabItem>
|
||||
<TabItem value="banana" label="Banana" attributes={{className: styles.yellow}}>
|
||||
This is a banana 🍌
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
`className` would be merged with other default class names. You may also use a custom `data-value` field (`{'data-value': 'apple'}`) paired with CSS attribute selectors:
|
||||
|
||||
```css title="styles.module.css"
|
||||
li[role='tab'][data-value='apple'] {
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Query string {#query-string}
|
||||
|
||||
It is possible to persist the selected tab into the url search parameters. This enables deep linking: the ability to share or bookmark a link to a specific tab, that will be pre-selected when the page loads.
|
||||
|
||||
Use the `queryString` prop to enable this feature and define the search param name to use.
|
||||
|
||||
```tsx
|
||||
// highlight-next-line
|
||||
<Tabs queryString="current-os">
|
||||
<TabItem value="android" label="Android">
|
||||
Android
|
||||
</TabItem>
|
||||
<TabItem value="ios" label="iOS">
|
||||
iOS
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs queryString='current-os'>
|
||||
<TabItem value="android" label="Android">Android</TabItem>
|
||||
<TabItem value="ios" label="iOS">iOS</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
As soon as a tab is clicked, a search parameter is added at the end of the url: `?current-os=android` or `?current-os=ios`.
|
||||
|
||||
:::tip
|
||||
|
||||
`queryString` can be used together with `groupId`.
|
||||
|
||||
For convenience, when the `queryString` prop is `true`, the `groupId` value will be used as a fallback.
|
||||
|
||||
```tsx
|
||||
// highlight-next-line
|
||||
<Tabs groupId="current-os" queryString>
|
||||
<TabItem value="android" label="Android">
|
||||
Android
|
||||
</TabItem>
|
||||
<TabItem value="ios" label="iOS">
|
||||
iOS
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<Tabs queryString groupId="current-os">
|
||||
<TabItem value="android" label="Android">Android</TabItem>
|
||||
<TabItem value="ios" label="iOS">iOS</TabItem>
|
||||
</Tabs>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
When the page loads, the tab query string choice will be restored in priority over the `groupId` choice (using `localStorage`).
|
||||
|
||||
:::
|
|
@ -0,0 +1,283 @@
|
|||
---
|
||||
id: toc
|
||||
description: Customizing headings and table-of-contents in Markdown
|
||||
slug: /markdown-features/toc
|
||||
---
|
||||
|
||||
import BrowserWindow from '@site/src/components/BrowserWindow';
|
||||
|
||||
# Headings and Table of contents
|
||||
|
||||
## Markdown headings {#markdown-headings}
|
||||
|
||||
You can use regular Markdown headings.
|
||||
|
||||
```md
|
||||
## Level 2 title
|
||||
|
||||
### Level 3 title
|
||||
|
||||
#### Level 4 title
|
||||
```
|
||||
|
||||
Each Markdown heading will appear as a table of contents entry.
|
||||
|
||||
### Heading IDs {#heading-ids}
|
||||
|
||||
Each heading has an ID that can be automatically generated or explicitly specified. Heading IDs allow you to link to a specific document heading in Markdown or JSX:
|
||||
|
||||
```md
|
||||
[link](#heading-id)
|
||||
```
|
||||
|
||||
```jsx
|
||||
<Link to="#heading-id">link</Link>
|
||||
```
|
||||
|
||||
By default, Docusaurus will generate heading IDs for you, based on the heading text. For example, `### Hello World` will have ID `hello-world`.
|
||||
|
||||
Generated IDs have **some limitations**:
|
||||
|
||||
- The ID might not look good
|
||||
- You might want to **change or translate** the text without updating the existing ID
|
||||
|
||||
A special Markdown syntax lets you set an **explicit heading id**:
|
||||
|
||||
```md
|
||||
### Hello World {#my-explicit-id}
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Use the **[`write-heading-ids`](../../cli.mdx#docusaurus-write-heading-ids-sitedir)** CLI command to add explicit IDs to all your Markdown documents.
|
||||
|
||||
:::
|
||||
|
||||
:::caution Avoid colliding IDs
|
||||
|
||||
Generated heading IDs will be guaranteed to be unique on each page, but if you use custom IDs, make sure each one appears exactly once on each page, or there will be two DOM elements with the same ID, which is invalid HTML semantics, and will lead to one heading being unlinkable.
|
||||
|
||||
:::
|
||||
|
||||
## Table of contents heading level {#table-of-contents-heading-level}
|
||||
|
||||
Each Markdown document displays a table of contents on the top-right corner. By default, this table only shows h2 and h3 headings, which should be sufficient for an overview of the page structure. In case you need to change the range of headings displayed, you can customize the minimum and maximum heading level — either per page or globally.
|
||||
|
||||
To set the heading level for a particular page, use the `toc_min_heading_level` and `toc_max_heading_level` front matter.
|
||||
|
||||
```md title="myDoc.md"
|
||||
---
|
||||
# Display h2 to h5 headings
|
||||
toc_min_heading_level: 2
|
||||
toc_max_heading_level: 5
|
||||
---
|
||||
```
|
||||
|
||||
To set the heading level for _all_ pages, use the [`themeConfig.tableOfContents`](../../api/themes/theme-configuration.mdx#table-of-contents) option.
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
tableOfContents: {
|
||||
// highlight-start
|
||||
minHeadingLevel: 2,
|
||||
maxHeadingLevel: 5,
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
If you've set the options globally, you can still override them locally via front matter.
|
||||
|
||||
:::note
|
||||
|
||||
The `themeConfig` option would apply to all TOC on the site, including [inline TOC](#inline-table-of-contents), but front matter options only affect the top-right TOC. You need to use the `minHeadingLevel` and `maxHeadingLevel` props to customize each `<TOCInline />` component.
|
||||
|
||||
:::
|
||||
|
||||
## Inline table of contents {#inline-table-of-contents}
|
||||
|
||||
It is also possible to display an inline table of contents directly inside a Markdown document, thanks to MDX.
|
||||
|
||||
The `toc` variable is available in any MDX document and contains all the headings of an MDX document. By default, only `h2` and `h3` headings are displayed in the TOC. You can change which heading levels are visible by setting `minHeadingLevel` or `maxHeadingLevel` for individual `TOCInline` components.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
<TOCInline toc={toc} />
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
<BrowserWindow>
|
||||
<TOCInline toc={toc} />
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
The `toc` global is just a list of heading items:
|
||||
|
||||
```ts
|
||||
declare const toc: {
|
||||
value: string;
|
||||
id: string;
|
||||
level: number;
|
||||
}[];
|
||||
```
|
||||
|
||||
Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree.
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```jsx
|
||||
import TOCInline from '@theme/TOCInline';
|
||||
|
||||
<TOCInline
|
||||
// Only show h2 and h4 headings
|
||||
toc={toc.filter((node) => node.level === 2 || node.level === 4)}
|
||||
minHeadingLevel={2}
|
||||
// Show h4 headings in addition to the default h2 and h3 headings
|
||||
maxHeadingLevel={4}
|
||||
/>
|
||||
```
|
||||
|
||||
```mdx-code-block
|
||||
<BrowserWindow>
|
||||
<TOCInline
|
||||
toc={toc.filter((node) => node.level === 2 || node.level === 4)}
|
||||
minHeadingLevel={2}
|
||||
maxHeadingLevel={4}
|
||||
/>
|
||||
</BrowserWindow>
|
||||
```
|
||||
|
||||
## Customizing table of contents generation {#customizing-table-of-contents-generation}
|
||||
|
||||
The table-of-contents is generated by parsing the Markdown source with a [Remark plugin](./markdown-features-plugins.mdx). There are known edge-cases where it generates false-positives and false-negatives.
|
||||
|
||||
Markdown headings within hideable areas will still show up in the TOC. For example, headings within [`Tabs`](./markdown-features-tabs.mdx) and [`details`](./markdown-features-intro.mdx#details) will not be excluded.
|
||||
|
||||
Non-Markdown headings will not show up in the TOC. This can be used to your advantage to tackle the aforementioned issue.
|
||||
|
||||
```md
|
||||
<details>
|
||||
<summary>Some details containing headings</summary>
|
||||
<h2 id="#heading-id">I'm a heading that will not show up in the TOC</h2>
|
||||
|
||||
Some content...
|
||||
|
||||
</details>
|
||||
```
|
||||
|
||||
The ability to ergonomically insert extra headings or ignore certain headings is a work-in-progress. If this feature is important to you, please report your use-case in [this issue](https://github.com/facebook/docusaurus/issues/6201).
|
||||
|
||||
---
|
||||
|
||||
:::caution
|
||||
|
||||
Below is just some dummy content to have more table of contents items available on the current page.
|
||||
|
||||
:::
|
||||
|
||||
## Example Section 1 {#example-section-1}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
### Example Subsection 1 a {#example-subsection-1-a}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 1 a I
|
||||
|
||||
#### Example subsubsection 1 a II
|
||||
|
||||
#### Example subsubsection 1 a III
|
||||
|
||||
### Example Subsection 1 b {#example-subsection-1-b}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 1 b I
|
||||
|
||||
#### Example subsubsection 1 b II
|
||||
|
||||
#### Example subsubsection 1 b III
|
||||
|
||||
### Example Subsection 1 c {#example-subsection-1-c}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 1 c I
|
||||
|
||||
#### Example subsubsection 1 c II
|
||||
|
||||
#### Example subsubsection 1 c III
|
||||
|
||||
## Example Section 2 {#example-section-2}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
### Example Subsection 2 a {#example-subsection-2-a}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 2 a I
|
||||
|
||||
#### Example subsubsection 2 a II
|
||||
|
||||
#### Example subsubsection 2 a III
|
||||
|
||||
### Example Subsection 2 b {#example-subsection-2-b}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 2 b I
|
||||
|
||||
#### Example subsubsection 2 b II
|
||||
|
||||
#### Example subsubsection 2 b III
|
||||
|
||||
### Example Subsection 2 c {#example-subsection-2-c}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 2 c I
|
||||
|
||||
#### Example subsubsection 2 c II
|
||||
|
||||
#### Example subsubsection 2 c III
|
||||
|
||||
## Example Section 3 {#example-section-3}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
### Example Subsection 3 a {#example-subsection-3-a}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 3 a I
|
||||
|
||||
#### Example subsubsection 3 a II
|
||||
|
||||
#### Example subsubsection 3 a III
|
||||
|
||||
### Example Subsection 3 b {#example-subsection-3-b}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 3 b I
|
||||
|
||||
#### Example subsubsection 3 b II
|
||||
|
||||
#### Example subsubsection 3 b III
|
||||
|
||||
### Example Subsection 3 c {#example-subsection-3-c}
|
||||
|
||||
Lorem ipsum
|
||||
|
||||
#### Example subsubsection 3 c I
|
||||
|
||||
#### Example subsubsection 3 c II
|
||||
|
||||
#### Example subsubsection 3 c III
|
Loading…
Add table
Add a link
Reference in a new issue