From bf9924a5f6137820090b5b9850a912eb06bd733d Mon Sep 17 00:00:00 2001 From: Balthasar Hofer Date: Mon, 5 Jan 2026 16:34:17 +0100 Subject: [PATCH] feat(mdx-loader): add admonitions directive support for class/id shortcuts (#11642) --- .../__tests__/__fixtures__/attributes.md | 21 ++++++ .../__snapshots__/index.test.ts.snap | 9 +++ .../admonitions/__tests__/index.test.ts | 5 ++ .../src/remark/admonitions/index.ts | 2 + .../src/theme-classic.d.ts | 2 + .../src/theme/Admonition/Layout/index.tsx | 10 +-- .../_docs tests/tests/admonitions.mdx | 67 +++++++++++++++++++ website/_dogfooding/dogfooding.css | 21 ++++++ .../markdown-features-admonitions.mdx | 48 +++++++++++++ 9 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__fixtures__/attributes.md diff --git a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__fixtures__/attributes.md b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__fixtures__/attributes.md new file mode 100644 index 000000000000..eb91dea38bbf --- /dev/null +++ b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__fixtures__/attributes.md @@ -0,0 +1,21 @@ +Admonitions with attributes + +:::info[Info Title]{.bold} +An info admonition with a className attribute. +::: + +:::info{.bold .italic} +An info admonition with multiple className attributes. +::: + +:::info{#custom-id} +An info admonition with a custom id attribute. +::: + +:::info{#custom-id .bold} +An info admonition with both id and className attributes. +::: + +:::info{.c1 #id1 .c2 #id2 hello=world} +Arbitrary attributes are ignored. +::: \ No newline at end of file diff --git a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap index c19b192babb0..23b93a2b663f 100644 --- a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/__snapshots__/index.test.ts.snap @@ -11,6 +11,15 @@ exports[`admonitions remark plugin add custom keyword 1`] = `

++++

" `; +exports[`admonitions remark plugin attributes 1`] = ` +"

Admonitions with attributes

+

An info admonition with a className attribute.

+

An info admonition with multiple className attributes.

+

An info admonition with a custom id attribute.

+

An info admonition with both id and className attributes.

+

Arbitrary attributes are ignored.

" +`; + exports[`admonitions remark plugin base 1`] = ` "

The blog feature enables you to deploy in no time a full-featured blog.

Check the Blog Plugin API Reference documentation for an exhaustive list of options.

diff --git a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts index 7784850e44e1..7629d8679401 100644 --- a/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts +++ b/packages/docusaurus-mdx-loader/src/remark/admonitions/__tests__/index.test.ts @@ -97,4 +97,9 @@ describe('admonitions remark plugin', () => { const result = await processFixture('nesting'); expect(result).toMatchSnapshot(); }); + + it('attributes', async () => { + const result = await processFixture('attributes'); + await expect(result).toMatchSnapshot(); + }); }); diff --git a/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts b/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts index d87df3bb54a5..15bfb37e5326 100644 --- a/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts +++ b/packages/docusaurus-mdx-loader/src/remark/admonitions/index.ts @@ -107,6 +107,8 @@ const plugin: Plugin[], Root> = function plugin( hName: 'admonition', hProperties: { ...(textOnlyTitle && {title: textOnlyTitle}), + ...(node.attributes?.class && {className: node.attributes.class}), + ...(node.attributes?.id && {id: node.attributes.id}), type: node.name, }, }; diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index c38431f8b7f4..961d68fcc044 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -48,6 +48,7 @@ declare module '@theme/Admonition' { readonly icon?: ReactNode; readonly title?: ReactNode; readonly className?: string; + readonly id?: string; } export default function Admonition(props: Props): ReactNode; @@ -123,6 +124,7 @@ declare module '@theme/Admonition/Layout' { readonly icon?: ReactNode; readonly title?: ReactNode; readonly className?: string; + readonly id?: string; } export default function AdmonitionLayout(props: Props): ReactNode; } diff --git a/packages/docusaurus-theme-classic/src/theme/Admonition/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/Admonition/Layout/index.tsx index b90b6cb1dbbc..521712de772c 100644 --- a/packages/docusaurus-theme-classic/src/theme/Admonition/Layout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Admonition/Layout/index.tsx @@ -17,7 +17,8 @@ function AdmonitionContainer({ type, className, children, -}: Pick & {children: ReactNode}) { + id, +}: Pick & {children: ReactNode}) { return (
+ )} + id={id}> {children}
); @@ -47,9 +49,9 @@ function AdmonitionContent({children}: Pick) { } export default function AdmonitionLayout(props: Props): ReactNode { - const {type, icon, title, children, className} = props; + const {type, icon, title, children, className, id} = props; return ( - + {title || icon ? : null} {children} diff --git a/website/_dogfooding/_docs tests/tests/admonitions.mdx b/website/_dogfooding/_docs tests/tests/admonitions.mdx index e9f7d858aae2..4a80c46b2734 100644 --- a/website/_dogfooding/_docs tests/tests/admonitions.mdx +++ b/website/_dogfooding/_docs tests/tests/admonitions.mdx @@ -54,6 +54,73 @@ import InfoIcon from "@theme/Admonition/Icon/Info" ``` +## Admonitions with attributes + +
+Relevant CSS for this section + +```css title="dogfooding.css" +/* ... */ +.shadow { + --shadow-color: red; + box-shadow: 10px 10px 10px var(--shadow-color); + + &.blue { + --shadow-color: blue; + } +} + +#info-1 { + border: solid 2px blue; +} + +#info-2 { + border: solid 2px green; +} + +#info-3 { + border: solid 2px red; +} +``` + +
+ +### Classes + +:::info{.shadow} + +The class `shadow` was added by writing `:::info{.shadow}`. + +::: + +:::info{.shadow .blue} + +The class `shadow` and `blue` were added by writing `:::info{.shadow .blue}`. + +::: + +### Ids + +:::info{#info-1} + +The id `info-1` was added by writing `:::{#info-1}` + +::: + +:::info{#info-3 #info-1 #info-2} + +The last provided id `info-2` wins when writing `:::{#info-3 #info-1 #info-2}` + +::: + +### Combination + +:::info{.shadow #info-4 .blue #info-3} + +Multiple classes and ids: `{.shadow #info-4 .blue #info-3}`. + +::: + ## Indented admonitions See admonition title v2 compat syntax bug: https://github.com/facebook/docusaurus/issues/9507 diff --git a/website/_dogfooding/dogfooding.css b/website/_dogfooding/dogfooding.css index 54376d3d546c..3ae643d6f197 100644 --- a/website/_dogfooding/dogfooding.css +++ b/website/_dogfooding/dogfooding.css @@ -25,6 +25,27 @@ html { border-bottom: solid thin cyan; } + .shadow { + --shadow-color: red; + box-shadow: 10px 10px 10px var(--shadow-color); + + &.blue { + --shadow-color: blue; + } + } + + #info-1 { + border: solid 2px blue; + } + + #info-2 { + border: solid 2px green; + } + + #info-3 { + border: solid 2px red; + } + .dogfood_sidebar_class_name_test { &.theme-doc-sidebar-item-link > a { color: cyan; diff --git a/website/docs/guides/markdown-features/markdown-features-admonitions.mdx b/website/docs/guides/markdown-features/markdown-features-admonitions.mdx index 39353f587396..60f8605ad347 100644 --- a/website/docs/guides/markdown-features/markdown-features-admonitions.mdx +++ b/website/docs/guides/markdown-features/markdown-features-admonitions.mdx @@ -129,6 +129,54 @@ Some **content** with some _Markdown_ `syntax`. ``` +## Specifying attributes {#specifying-attributes} + +You may also provide classes or IDs to admonitions. + +```md +:::note[With css classes]{.padding--lg .text--italic} + +Note the padding and the italicized text. + +::: + +:::note{#admonition-id} + +The admonition container has now the id `admonition-id`. + +::: + +:::note{.padding--lg #admonition-id-2} + +Use id and classes together. + +::: +``` + +```mdx-code-block + + +:::note[With css classes]{.padding--lg .text--italic} + +Note the padding and the italicized text. + +::: + +:::note{#admonition-id} + +The admonition container has now the id `admonition-id`. + +::: + +:::note{.padding--lg #admonition-id-2} + +Use id and classes together. + +::: + + +``` + ## Nested admonitions {#nested-admonitions} Admonitions can be nested. Use more colons `:` for each parent admonition level.