This guide has made slight changes based on the markdown-mdx-extended-features. Thank you to the original author for efforts. Stephanie Lin
Calloutsh2
Supported by the , you can configure the plugin in rehype-calloutsplugins/index.ts
.
If you change the theme
configuration (default: 'vitepress'
), you will also need to update the imported CSS file in src/styles/pro.css
(@import 'rehype-callouts/theme/yourconfig'
).
<!-- Callout type names are case-insensitive: 'Note', 'NOTE', and 'note' are equivalent. -->
<!-- vitepress -->
<!-- This is a _non-collapsible_ callout -->> [!note]> Note content.
> [!tip]> Tip content.
> [!important]> Important content.
> [!warning]> Warning content.
> [!caution]> Caution content.
> [!caution]- This is a **collapsible** callout> Caution content.
> [!note]+ This is a **collapsible** callout> Note content.
Note content.
Tip content.
Important content.
Warning content.
Caution content.
This is a collapsible callout
Caution content.
This is a collapsible callout
Note content.
Fully-featured Code Blocksh2
Supported by with astro-expressive-code@expressive-code/plugin-collapsible-sections and @expressive-code/plugin-line-numbers plugins to add styling and extra functionality for code blocks.
To customize code block themes or functionality, modify the ec.config.mjs
file at the project root after reviewing the , such as Configuring Expressive Codechange themes, enable word wrap, or toggle line numbers.
Here’s a quick preview of what’s possible. Check the detailed guide for more info.
Syntax highlightingh4
console.log('This code is syntax highlighted!')
ANSI colors:- Regular: Red Green Yellow Blue Magenta Cyan- Bold: Red Green Yellow Blue Magenta Cyan- Dimmed: Red Green Yellow Blue Magenta Cyan
256 colors (showing colors 160-177):160 161 162 163 164 165166 167 168 169 170 171172 173 174 175 176 177
Full RGB colors:ForestGreen - RGB(34, 139, 34)
Text formatting: Bold Dimmed Italic Underline
Code editor framesh5
// Use `title="my-test-file.js"`console.log('Title attribute example')
// Use `// src/content/index.ts`console.log('File name comment example')
Terminal framesh5
echo "This terminal frame has no title"
Write-Output "This one has a title!"
Marking full lines & line rangesh5
// Line 1 - targeted by line number// Line 2// Line 3// Line 4 - targeted by line number// Line 5// Line 6// Line 7 - targeted by range "7-8"// Line 8 - targeted by range "7-8"
Selecting line marker types (mark, ins, del)h5
function demo() { console.log('this line is marked as deleted') // This line and the next one are marked as inserted console.log('this is the second inserted line')
return 'this line uses the neutral default marker type'}
Adding labels to line markersh5
<button role="button" {...props} value={value} className={buttonClassName} disabled={disabled} active={active}> {children && !active && (typeof children === 'string' ? <span>{children}</span> : children)}</button>
Adding long labels on their own linesh5
<button role="button" {...props}
value={value} className={buttonClassName}
disabled={disabled} active={active}>
{children && !active && (typeof children === 'string' ? <span>{children}</span> : children)}</button>
Using diff-like syntaxh5
this line will be marked as insertedthis line will be marked as deletedthis is a regular line
function thisIsJavaScript() { // This entire block gets highlighted as JavaScript, // and we can still add diff markers to it! console.log('Old code to be removed') console.log('New and shiny code!')}
Marking individual text inside linesh5
// Plaintext search stringsfunction demo() { // Mark any given text inside lines return 'Multiple matches of the given text are supported'}
Marking individual text inside linesh5
// Regular expressionsconsole.log('The words yes and yep will be marked.')
# Regular expressionsecho "Test" > /home/test.txt
// Regular expressionsIf you only want to mark certain parts matched by your regular expression, you can use capture groups.
For example, the expression `/ye(s|p)/` will match yes and yep, but only mark the character s or p:
// Regular expressionsTo prevent this special treatment of capture groups, you can convert them to non-capturing groups by adding ?: after the opening parenthesis. For example:
This block uses `/ye(?:s|p)/`, which causes the fullmatching words "yes" and "yep" to be marked.
// Selecting inline marker types (mark, ins, del)function demo() { console.log('These are inserted and deleted marker types'); // The return statement uses the default marker type return true;}
Configuring word wrap per blockh5
// Example with wrapfunction getLongString() { return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'}
// Example with wrap=falsefunction getLongString() { return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'}
Configuring indentation of wrapped linesh5
// Example with preserveIndent (enabled by default)function getLongString() { return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'}
// Example with preserveIndent=falsefunction getLongString() { return 'This is a very long string that will most probably not fit into the available space unless the container is extremely wide'}
Collapsible sectionsh5
5 collapsed lines
// All this boilerplate setup code will be collapsedimport { someBoilerplateEngine } from '@example/some-boilerplate'import { evenMoreBoilerplate } from '@example/even-more-boilerplate'
const engine = someBoilerplateEngine(evenMoreBoilerplate())
// This part of the code will be visible by defaultengine.doSomething(1, 2, 3, calcFn)
function calcFn() { // You can have multiple collapsed sections3 collapsed lines
const a = 1 const b = 2 const c = a + b
// This will remain visible console.log(`Calculation result: ${a} + ${b} = ${c}`) return c}
4 collapsed lines
// All this code until the end of the block will be collapsed againengine.closeConnection()engine.freeMemory()engine.shutdown({ reason: 'End of example boilerplate code' })
Displaying line numbers per blockh5
// This code block will show line numbersconsole.log('Greetings from line 2!')console.log('I am on line 3')
// Line numbers are disabled for this blockconsole.log('Hello?')console.log('Sorry, do you know what line I am on?')
// Changing the starting line numberconsole.log('Greetings from line 5!')console.log('I am on line 6')
Image Caption & Linkh2
Use the :::image
directive from to wrap images in a container for captions, clickable links, and more. Customize via the remark-directive-sugarimage
option in plugins/index.ts
(remarkDirectiveSugar
) and style under /* :::image */
in src/styles/pro.css
.
:::image-figure
h3
:::image-figure[caption]{<figcaption> attrs}
: The square brackets define the <figcaption>
text (defaults to the alt text from ![]()
if omitted), while the curly braces are used for inline styles or supported attributes to the generated <figcaption>
element.
(<img> attrs)
: Standard Markdown image with optional attributes in parentheses, enabled by , for customizing the generated remark-imgattr<img>
element.
:::image-figure[caption]{<figcaption> attrs}
: The square brackets define the <figcaption>
text (defaults to the alt text from ![]()
if omitted), while the curly braces are used for inline styles or supported attributes to the generated <figcaption>
element.
(<img> attrs)
: Standard Markdown image with optional attributes in parentheses, enabled by , for customizing the generated remark-imgattr<img>
element.
:::image-figure[This Is a **Figcaption** with _`<figure>` Attrs_]{style="text-align:center;color:orange"}:::
:::image-figure[This is a **figcaption** with _`<img>` attrs_.](style: width:600px;):::
<!-- 💡 Use `(class:no-zoom)` to disable zoom -->:::image-figure[This is a **figcaption** with `class:no-zoom`.](class:no-zoom):::
<!-- 💡 If no `[caption]`, use `[alt]` as figcaption. -->:::image-figure![If `[caption]` not set, the alt text from `![]()` will be used as the figcaption.](~/assets/images/markdown-extension-syntax/markdown-extension-syntax.png):::
<!-- 💡 Images for light (img-light) and dark (img-dark) modes --><!-- ⚠️ At least one line must separate two image syntaxes (![]()), or won't work. -->:::image-figure[This example shows different images for light (add `class:img-light`) and dark (add `class:img-dark`) modes.](class:img-light)
(class:img-dark):::
<!-- ❌ If no text is available for the figcaption, it won't work. -->:::image-figure:::

<figure>
Attrs
<img>
attrs.
class:no-zoom
.![If [caption] not set, the alt text from ![]() will be used as the figcaption.](/_astro/markdown-extension-syntax.BiHTVPdZ_JTw5d.webp)


class:img-light
) and dark (add class:img-dark
) modes.Setting an image’s width
attribute directly may cause blurriness. Learn more
:::image-a
h3
The custom directive wraps an image inside a link, making it clickable.
:::image-a{<a> attrs}
: Define the link (href), styles, or classes in the curly braces for <a>
element.
(<img> attrs)
: Same as above.
:::image-a{href="https://github.com/Dnzzk2/Litos"}:::
:::image-a{href="https://github.com/Dnzzk2/Litos" style="display:block" .custom-class}(style: margin-bottom: -1rem; transform:scaleX(1.1) scaleY(1.1);, loading: eager):::
::::image-a{href="https://github.com/Dnzzk2/Litos"}:::image-figure[This example shows `:::image-a` wraps around `:::image-figure` (both are interchangeable).]:::::::
<!-- ❌ No external links provided, it won't work.-->:::image-a:::



:::image-a
wraps around :::image-figure
(both are interchangeable).:::image-figure-polaroidh3
Polaroid style images with a border and shadow.
In order to ensure the style size on the phone, I have set a minimum width of 300px, and you can modify and expand the style in src/styles/picture.css
.
:::::image-div-polaroid:::image-figure-polaroid[This is a **figcaption** with _`<img>` attrs_.]::::::::
:::::image-div-polaroid:::image-figure-polaroid
markdown-extension-syntax.png::::::::
:::::image-div-polaroid:::image-figure-polaroid::::::::
<!-- change style -->:::::image-div-polaroid:::image-figure-polaroid{style="width:500px;"}::::::::
This is a figcaption with <img>
attrs.


markdown-extension-syntax.png


Video Embeddingh2
Use the ::video
directive from for consistent video embedding across different platforms. Customize via the remark-directive-sugarvideo
option in plugins/index.ts
and style under /* ::video */
in src/styles/pro.css
.
Say example.md
contains:
<!-- Embed a YouTube video -->::video-youtube{#gxBkghlglTg}
<!-- Embed a Bilibili video with a custom `title` attr -->::video-bilibili[custom title]{id=BV1MC4y1c7Kv}
<!-- Embed a Vimeo video with class `no-scale` to disable scaling -->::video-vimeo{id=912831806 class='no-scale'}<!-- ::video-vimeo{id=912831806 .no-scale} -->
<!-- Embed a custom video URL (must use `id`, not `#`) -->::video{id=https://www.youtube-nocookie.com/embed/gxBkghlglTg}
Then example.mdx
renders as:
Styled Link(:link
)h2
Use the :link
directive from to add links with avatars or favicons for GitHub, npm, or custom URLs. Customize via the remark-directive-sugarlink
option in plugins/index.ts
and style under /* :link */
in src/styles/pro.css
.
Link to a GitHub user or organization (prepend id
with @
)
Example 1: :link[Dnzzk2]{#@Dnzzk2}
links to the GitHub profile of the project maintainer, . Dnzzk2
Example 2: :link[Vite]{id=@vitejs}
links to the GitHub profile of the organization. Vite
Example 3: :link{#@Dnzzk2 tab=repositories}
links directly to the repositories tab of the GitHub user, like . For GitHub users, valid Dnzzk2tab
options: 'repositories','projects', 'packages', 'stars', 'sponsoring', 'sponsors'
.
Example 4: :link{#@vitejs tab=org-people}
links directly to the people section of a GitHub organization, like . For GitHub organizations, valid vitejstab
options: 'org-repositories', 'org-projects', 'org-packages', 'org-sponsoring', and 'org-people'
.
Link to a GitHub repository
Example 5: :link[Astro]{#withastro/astro}
or :link[Astro]{id=withastro/astro}
creates a link to repo. Astro
Link to an npm package
Example 6: :link{#remark-directive-sugar}
links to the npm homepage of the . remark-directive-sugar
Example 7: :link{id=remark-directive-sugar tab=dependencies}
links to the dependencies section of the on npm. For npm package, valid remark-directive-sugartab
options: 'readme', 'code', 'dependencies', 'dependents', and 'versions'
.
Link to a custom URL (must use id
, not #
)
Example 8: :link{id=https://developer.mozilla.org/en-US/docs/Web/JavaScript}
creates an external link to the . developer.mozilla.org/en-US/docs/Web...
Example 9: :link[Google]{id=https://www.google.com/}
creates an external link to the . Google
Customization
Example 10: :link[Vite]{id=@vitejs url=https://vite.dev/}
creates a to Vitehttps://vite.dev/
instead of https://github.com/vitejs
by using the url
.
Example 11: :link[Vite]{id=@vitejs img=https://vitejs.dev/logo.svg}
creates a that displays a custom logo by using the Viteimg
.
Example 12: :link{id=Dnzzk2/Litos class=github}
creates a with Dnzzk2/Litosclass=github
(or .github
) to override the default style of a GitHub repository.
Example 13: :link[Litos Themes]{id=https://github.com/Dnzzk2/Litos img=https://github.githubassets.com/assets/mona-e50f14d05e4b.png}
fully customizes a link. Litos Themes
Badgesh2
Use the :badge
directive from to display small pieces of information, such as status or category. remark-directive-sugar
The theme provides the following one predefined badges. You can customize them via the badge
option in plugins/index.ts
and style them under /* :badge */
in src/styles/pro.css
.
badge-n
: NEW
Additionally, you can direct use :badge[text]{attrs}
for easy visual customization of badges. For example: :badge[ISSUE]{style="background-color: #bef264"}
will display as ISSUE. If no color is specified, the default appearance will look like This.
Details Dropdownh2
:::details::summary[Details Dropdown]- List item 1- List item 2- List item 3- List item 4:::
Details Dropdown
- List item 1
- List item 2
- List item 3
- List item 4
Additionally, it also supports usage similar to the examples in remark-directive.
Thank you once again to the original author for their development, which has enabled this theme to have such excellent extension functions 💗. Stephanie Lin