diff --git a/packages/docusaurus-mdx-loader/src/loader.ts b/packages/docusaurus-mdx-loader/src/loader.ts
index 84addfd3f3f6..ec38eae9cd59 100644
--- a/packages/docusaurus-mdx-loader/src/loader.ts
+++ b/packages/docusaurus-mdx-loader/src/loader.ts
@@ -12,6 +12,7 @@ import {
parseMarkdownContentTitle,
escapePath,
getFileLoaderUtils,
+ escapeMarkdownHeadingIds,
} from '@docusaurus/utils';
import emoji from 'remark-emoji';
@@ -171,9 +172,14 @@ export async function mdxLoader(
const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
- const {content, contentTitle} = parseMarkdownContentTitle(contentWithTitle, {
- removeContentTitle: reqOptions.removeContentTitle,
- });
+ const {content: contentUnescaped, contentTitle} = parseMarkdownContentTitle(
+ contentWithTitle,
+ {
+ removeContentTitle: reqOptions.removeContentTitle,
+ },
+ );
+
+ const content = escapeMarkdownHeadingIds(contentUnescaped);
const hasFrontMatter = Object.keys(frontMatter).length > 0;
diff --git a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts
index 42df2a38d4f1..9acb4ca73b44 100644
--- a/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts
+++ b/packages/docusaurus-utils/src/__tests__/markdownUtils.test.ts
@@ -12,6 +12,7 @@ import {
parseMarkdownString,
parseMarkdownHeadingId,
writeMarkdownHeadingId,
+ escapeMarkdownHeadingIds,
} from '../markdownUtils';
describe('createExcerpt', () => {
@@ -882,6 +883,140 @@ describe('parseMarkdownHeadingId', () => {
});
});
+describe('escapeMarkdownHeadingIds', () => {
+ it('can escape simple heading id', () => {
+ expect(escapeMarkdownHeadingIds('# title 1 {#id-1}')).toBe(
+ '# title 1 \\{#id-1}',
+ );
+ expect(escapeMarkdownHeadingIds('# title 1 {#id-1}')).toBe(
+ '# title 1 \\{#id-1}',
+ );
+ expect(escapeMarkdownHeadingIds('# title 1{#id-1}')).toBe(
+ '# title 1\\{#id-1}',
+ );
+ expect(escapeMarkdownHeadingIds('# title 1 \\{#id-1}')).toBe(
+ '# title 1 \\{#id-1}',
+ );
+ expect(escapeMarkdownHeadingIds('# title 1\\{#id-1}')).toBe(
+ '# title 1\\{#id-1}',
+ );
+ });
+
+ it('can escape level 1-6 heading ids', () => {
+ expect(
+ escapeMarkdownHeadingIds(dedent`
+ # title 1 {#id-1}
+
+ ## title 2 {#id-2}
+
+ ### title 3 {#id-3}
+
+ #### title 4 {#id-4}
+
+ ##### title 5 {#id-5}
+
+ ###### title 6 {#id-6}
+ `),
+ ).toEqual(dedent`
+ # title 1 \{#id-1}
+
+ ## title 2 \{#id-2}
+
+ ### title 3 \{#id-3}
+
+ #### title 4 \{#id-4}
+
+ ##### title 5 \{#id-5}
+
+ ###### title 6 \{#id-6}
+ `);
+ });
+
+ it('does not escape level 7 heading id', () => {
+ expect(
+ escapeMarkdownHeadingIds(dedent`
+ ####### title 7 {#id-7}
+ `),
+ ).toEqual(dedent`
+ ####### title 7 {#id-7}
+ `);
+ });
+
+ it('does not escape non-heading', () => {
+ expect(
+ escapeMarkdownHeadingIds(dedent`
+ some text {#non-id}
+ `),
+ ).toEqual(dedent`
+ some text {#non-id}
+ `);
+ });
+
+ it('real world', () => {
+ expect(
+ escapeMarkdownHeadingIds(dedent`
+ # Support
+
+ Docusaurus has a community of thousands of developers.
+
+ On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
+
+ Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
+
+ ## Stack Overflow {#stack-overflow}
+
+ Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
+
+ ## Discussion forums \{#discussion-forums}
+
+ There are many online forums for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
+
+ - [Docusaurus online chat](https://discord.gg/docusaurus)
+ - [#help-and-questions](https://discord.gg/fwbcrQ3dHR) for user help
+ - [#contributors](https://discord.gg/6g6ASPA) for contributing help
+ - [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
+
+ ## Feature requests {#feature-requests}
+
+ For new feature requests, you can create a post on our [feature requests board (Canny)](/feature-requests), which is a handy tool for road-mapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
+
+ ## News {#news}
+
+ For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
+ `),
+ ).toEqual(dedent`
+ # Support
+
+ Docusaurus has a community of thousands of developers.
+
+ On this page we've listed some Docusaurus-related communities that you can be a part of; see the other pages in this section for additional online and in-person learning materials.
+
+ Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
+
+ ## Stack Overflow \{#stack-overflow}
+
+ Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
+
+ ## Discussion forums \{#discussion-forums}
+
+ There are many online forums for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
+
+ - [Docusaurus online chat](https://discord.gg/docusaurus)
+ - [#help-and-questions](https://discord.gg/fwbcrQ3dHR) for user help
+ - [#contributors](https://discord.gg/6g6ASPA) for contributing help
+ - [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
+
+ ## Feature requests \{#feature-requests}
+
+ For new feature requests, you can create a post on our [feature requests board (Canny)](/feature-requests), which is a handy tool for road-mapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
+
+ ## News \{#news}
+
+ For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
+ `);
+ });
+});
+
describe('writeMarkdownHeadingId', () => {
it('works for simple level-2 heading', () => {
expect(writeMarkdownHeadingId('## ABC')).toBe('## ABC {#abc}');
diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts
index ba74f8d3d134..026a83f76681 100644
--- a/packages/docusaurus-utils/src/index.ts
+++ b/packages/docusaurus-utils/src/index.ts
@@ -66,6 +66,7 @@ export {
} from './tags';
export {
parseMarkdownHeadingId,
+ escapeMarkdownHeadingIds,
createExcerpt,
parseFrontMatter,
parseMarkdownContentTitle,
diff --git a/packages/docusaurus-utils/src/markdownUtils.ts b/packages/docusaurus-utils/src/markdownUtils.ts
index 512a09bf916d..e0f67c4c3dcf 100644
--- a/packages/docusaurus-utils/src/markdownUtils.ts
+++ b/packages/docusaurus-utils/src/markdownUtils.ts
@@ -39,6 +39,23 @@ export function parseMarkdownHeadingId(heading: string): {
return {text: heading, id: undefined};
}
+/**
+ * MDX 2 requires escaping { with a \ so our anchor syntax need that now.
+ * See https://mdxjs.com/docs/troubleshooting-mdx/#could-not-parse-expression-with-acorn-error
+ */
+export function escapeMarkdownHeadingIds(content: string): string {
+ const markdownHeadingRegexp = /(?:^|\n)#{1,6}(?!#).*/g;
+ return content.replaceAll(markdownHeadingRegexp, (substring, ...args) =>
+ // TODO probably not the most efficient impl...
+ (
+ substring
+ .replace('{#', '\\{#')
+ // prevent duplicate escaping
+ .replace('\\\\{#', '\\{#')
+ )
+ );
+}
+
// TODO: Find a better way to do so, possibly by compiling the Markdown content,
// stripping out HTML tags and obtaining the first line.
/**
diff --git a/website/community/0-support.md b/website/community/0-support.md
index 7cd91a965e40..fcfa72185292 100644
--- a/website/community/0-support.md
+++ b/website/community/0-support.md
@@ -6,11 +6,11 @@ On this page we've listed some Docusaurus-related communities that you can be a
Before participating in Docusaurus' communities, [please read our Code of Conduct](https://engineering.fb.com/codeofconduct/). We have adopted the [Contributor Covenant](https://www.contributor-covenant.org/) and we expect that all community members adhere to the guidelines within.
-## Stack Overflow \{#stack-overflow}
+## Stack Overflow {#stack-overflow}
Stack Overflow is a popular forum to ask code-level questions or if you're stuck with a specific error. Read through the [existing questions](https://stackoverflow.com/questions/tagged/docusaurus) tagged with **docusaurus** or [ask your own](https://stackoverflow.com/questions/ask?tags=docusaurus)!
-## Discussion forums \{#discussion-forums}
+## Discussion forums {#discussion-forums}
There are many online forums for discussion about best practices and application architecture as well as the future of Docusaurus. If you have an answerable code-level question, Stack Overflow is usually a better fit.
@@ -19,10 +19,10 @@ There are many online forums for discussion about best practices and application
- [#contributors](https://discord.gg/6g6ASPA) for contributing help
- [Reddit's Docusaurus community](https://www.reddit.com/r/docusaurus/)
-## Feature requests \{#feature-requests}
+## Feature requests {#feature-requests}
For new feature requests, you can create a post on our [feature requests board (Canny)](/feature-requests), which is a handy tool for road-mapping and allows for sorting by upvotes, which gives the core team a better indicator of what features are in high demand, as compared to GitHub issues which are harder to triage. Refrain from making a Pull Request for new features (especially large ones) as someone might already be working on it or will be part of our roadmap. Talk to us first!
-## News \{#news}
+## News {#news}
For the latest news about Docusaurus, [follow **@docusaurus** on Twitter](https://twitter.com/docusaurus) and the [official Docusaurus blog](/blog) on this website.
diff --git a/website/community/1-team.mdx b/website/community/1-team.mdx
index 26726899a839..98bf339e27c2 100644
--- a/website/community/1-team.mdx
+++ b/website/community/1-team.mdx
@@ -6,7 +6,7 @@ import {
StudentFellowsTeamRow,
} from '@site/src/components/TeamProfileCards';
-## Active Team \{#active-team}
+## Active Team {#active-team}
The Docusaurus team works on the core functionality, plugins for the classic theme, as well as the Docusaurus documentation website.
@@ -14,19 +14,19 @@ Current members of the Docusaurus team are listed in alphabetical order below.
-## Honorary Alumni \{#honorary-alumni}
+## Honorary Alumni {#honorary-alumni}
Docusaurus would never be what it is today without the huge contributions from these folks who have moved on to bigger and greater things.
-## Student Fellows \{#student-fellows}
+## Student Fellows {#student-fellows}
A handful of students have also worked on Docusaurus as part of their school term/internship and the [Major League Hacking Fellowship program](https://fellowship.mlh.io/), contributing amazing features such as plugin options validation, migration tooling, and a Bootstrap theme.
-## Acknowledgements \{#acknowledgements}
+## Acknowledgements {#acknowledgements}
Docusaurus was originally created by Joel Marcey. Today, Docusaurus has a few hundred open source contributors. We’d like to recognize a few people who have made significant contributions to Docusaurus and its documentation in the past and have helped maintain them over the years:
diff --git a/website/community/2-resources.md b/website/community/2-resources.md
index 62b818e93f34..10d354017431 100644
--- a/website/community/2-resources.md
+++ b/website/community/2-resources.md
@@ -2,22 +2,22 @@
A curated list of interesting Docusaurus community projects.
-## Videos \{#videos}
+## Videos {#videos}
- [F8 2019: Using Docusaurus to Create Open Source Websites](https://www.youtube.com/watch?v=QcGJsf6mgZE)
-## Articles \{#articles}
+## Articles {#articles}
- [Awesome Docusaurus](https://github.com/webbertakken/awesome-docusaurus#readme) - Community curated list of Docusaurus resources.
- [Live code editing in Docusaurus](https://dev.to/mrmuhammadali/live-code-editing-in-docusaurus-ux-at-its-best-2hj1)
-## Showcase \{#showcase}
+## Showcase {#showcase}
See the showcase.
-## Community plugins \{#community-plugins}
+## Community plugins {#community-plugins}
-### Search \{#search}
+### Search {#search}
- [docusaurus-plugin-lunr](https://github.com/daldridge/docusaurus-plugin-lunr) - Docusaurus v2 plugin to create a local search index for use with Lunr.js
- [docusaurus-lunr-search](https://github.com/lelouch77/docusaurus-lunr-search) - Offline Search for Docusaurus v2
@@ -25,14 +25,14 @@ See the showcase
- [@easyops-cn/docusaurus-search-local](https://github.com/easyops-cn/docusaurus-search-local) - Offline/local search for Docusaurus v2 (language of zh supported)
- [docusaurus-theme-search-typesense](https://github.com/typesense/docusaurus-theme-search-typesense) - Docusaurus v2 plugin for [Typesense DocSearch](https://typesense.org/docs/latest/guide/docsearch.html).
-### Integrations \{#integrations}
+### Integrations {#integrations}
- [docusaurus2-dotenv](https://github.com/jonnynabors/docusaurus2-dotenv) - A Docusaurus 2 plugin that supports dotenv and other environment variables
- [posthog-docusaurus](https://github.com/PostHog/posthog-docusaurus) - Integrate [PostHog](https://posthog.com/) product analytics with Docusaurus v2
- [docusaurus-plugin-moesif](https://github.com/Moesif/docusaurus-plugin-moesif) - Adds [Moesif API Analytics](https://www.moesif.com/) to track user behavior and pinpoint where developers drop off in your activation funnel.
- [docusaurus-plugin-yandex-metrica](https://github.com/sgromkov/docusaurus-plugin-yandex-metrica) - Adds [Yandex Metrika](https://metrika.yandex.ru/) counter for evaluating site traffic and analyzing user behavior.
-### Features \{#features}
+### Features {#features}
- [docusaurus-theme-github-codeblock](https://github.com/saucelabs/docusaurus-theme-github-codeblock). A Docusaurus v2 plugin that supports referencing code examples from public GitHub repositories
- [mr-pdf](https://github.com/kohheepeace/mr-pdf) - Generate documentation into PDF format, suitable for Docusaurus v1 and v2 (including beta versions)
@@ -50,7 +50,7 @@ See the showcase
- [docusaurus-openapi-docs](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs) - A Docusaurus v2 plugin and theme for generating interactive OpenAPI docs
- [docusaurus-post-generator](https://github.com/moojing/docusaurus-post-generator) - A command line tool for user to add a blog/doc file quickly by command like `yarn gen-post new [template] [post_name]`.
-## Enterprise usage \{#enterprise-usage}
+## Enterprise usage {#enterprise-usage}
- Facebook
- Google
diff --git a/website/community/5-release-process.md b/website/community/5-release-process.md
index 267dfed877e7..4c76f0e563da 100644
--- a/website/community/5-release-process.md
+++ b/website/community/5-release-process.md
@@ -8,7 +8,7 @@ This topic is particularly important for highly customized sites that may have d
:::
-## Semantic versioning \{#semantic-versioning}
+## Semantic versioning {#semantic-versioning}
Docusaurus versioning is based on the `major.minor.patch` scheme and respects [Semantic Versioning](https://semver.org/).
@@ -27,7 +27,7 @@ Releasing Docusaurus 2.0 took a very long time. From now on, Docusaurus will **r
:::
-### Major versions \{#major-versions}
+### Major versions {#major-versions}
The `major` version number is incremented on **every breaking change**.
@@ -42,7 +42,7 @@ Read our [public API surface](#public-api-surface) section to clearly understand
:::
-### Minor versions \{#minor-versions}
+### Minor versions {#minor-versions}
The `minor` version number is incremented on every significant retro-compatible change.
@@ -57,7 +57,7 @@ If you only use our [public API surface](#public-api-surface), you should be abl
:::
-### Patch versions \{#patch-versions}
+### Patch versions {#patch-versions}
The `patch` version number is incremented on bugfixes releases.
@@ -65,7 +65,7 @@ Whenever a new patch version is released, we publish:
- an exhaustive changelog entry
-## Versions \{#versions}
+## Versions {#versions}
```mdx-code-block
import {
@@ -87,7 +87,7 @@ The branch is created just before releasing the first v
:::
-### Stable version \{#stable-version}
+### Stable version {#stable-version}
The stable version (v, on ) is recommended for most Docusaurus users.
@@ -101,7 +101,7 @@ It is recommended to upgrade within that time frame to the new stable version.
:::
-### Next version \{#next-version}
+### Next version {#next-version}
The next version (v, on ) is the version the Docusaurus team is currently working on.
@@ -129,7 +129,7 @@ At the `beta` and `rc` (release candidate) phases, we avoid introducing major br
:::
-## Public API surface \{#public-api-surface}
+## Public API surface {#public-api-surface}
Docusaurus commits to respecting Semantic Versioning. This means that whenever changes occur in Docusaurus public APIs and break backward compatibility, we will increment the `major` version number.
@@ -141,7 +141,7 @@ Docusaurus guarantees public API retro-compatibility across `minor` versions. Un
We will outline what accounts as the public API surface.
-### Core public API \{#core-public-api}
+### Core public API {#core-public-api}
✅ Our public API includes:
@@ -164,7 +164,7 @@ For non-theme APIs, any documented API is considered public (and will be stable)
An API being "stable" means if you increment the patch or minor version of your Docusaurus installation without any other change, running `docusaurus start` or `docusaurus build` should not throw an error.
-### Theming public API \{#theming-public-api}
+### Theming public API {#theming-public-api}
Docusaurus has a very flexible theming system: