rehype-callout

introduction

This is a rehype plugin that parses Obsidian’s callout syntax

github repo

npm package

ES Module only

features

title and content can be formatted as normal markdown

del em strong red
>[!example] ~~del~~ *em* **strong** <span style="color: red">red</span>

support all obsidan callout types

nested callouts

outer callout

outer content

nested callout
>[!note] outer callout
> outer content
>>[!success] nested callout
outer title

outer content

nested callout

nested content

foldable with + or -

A plus sign expands the callout by default, and a minus sign collapses it instead.

Are callouts foldable?

Yes! In a foldable callout, the contents are hidden when the callout is collapsed.

Are callouts foldable?

Yes! In a foldable callout, the contents are hidden when the callout is collapsed.

usage

install
npm install rehype-callout
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import callout from "rehype-callout";
const md = `>[!note] This is a **note** callout.
> 你好!
> ## inner title
> This is the content!`;
const output = unified()
.use(remarkParse)
.use(remarkRehype)
.use(callout, {}) /* second param is custom config options */
.use(rehypeStringify)
.processSync(md);
console.log(String(output))

The generated HTML of the above code would be:

<blockquote data-callout="note">
<div class="callout-title">
<div class="callout-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="2" x2="22" y2="6"></line>
<path d="M7.5 20.5 19 9l-4-4L3.5 16.5 2 22z"></path>
</svg></div>
<div class="callout-title-inner">This is a<strong>note</strong>callout.</div>
</div>
<div class="callout-content">
<p>你好!</p>
<h2>inner title</h2>
<p>This is the content!</p>
</div>
</blockquote>

in Astro:

astro.config.mjs
import rehypeCallout from 'rehype-callout';
// https://astro.build/config
export default defineConfig({
// ...
markdown:{
rehypePlugins:[rehypeCallout],
}
});

Configuration

/** @type {import('rehype-callout').Config} */
const calloutOptions = {
...
}
export interface Config {
/**
* Class names with prefix are embedded in the generated HTML,
* to avoid css confilict, customize the prefix.
* @default "callout"
*/
prefix: string;
/**
* an Object that maps callout type to svg icon string.
* type must be lowercase.
* @example {info: '<svg>...</svg>', ...}
* @default see docs website.
*/
types: Record<string, string>;
/**
* an svg icon string to indicate expandable
*/
expandIcon: string;
/**
* add more class names to the callout container
* @example Undoing tailwindcss-typography by class "not-prose",
* ```js
// astro.config.mjs
import rehypeCallout from 'rehype-callout';
export default defineConfig({
markdown:{
rehypePlugins: [[rehypeCallout,{customClassNames:['not-prose']}]],
}
});
```
*/
customClassNames: string[];
}

default config:

const defaultConfig: Config = {
prefix: "callout",
expandIcon: expandIcon,
//types refer to https://help.obsidian.md/Editing+and+formatting/Callouts#Supported+types
types: {
note: pencilIcon,
abstract: clipboardListIcon,
summary: clipboardListIcon,
tldr: clipboardListIcon,
info: infoIcon,
todo: checkCircleIcon,
tip: flameIcon,
hint: flameIcon,
important: flameIcon,
success: checkIcon,
check: checkIcon,
done: checkIcon,
question: helpCircleIcon,
help: helpCircleIcon,
faq: helpCircleIcon,
warning: alertTriangleIcon,
attention: alertTriangleIcon,
caution: alertTriangleIcon,
failure: xIcon,
missing: xIcon,
fail: xIcon,
danger: zapIcon,
error: zapIcon,
bug: bugIcon,
example: listIcon,
quote: quoteIcon,
cite: quoteIcon,
},
customClassNames: [],
};

style callouts

Class names are embedded in the generated HTML, so you can style them in your CSS.

a preset css file is provided in: node_modules/rehype-callout/callout.css, you can import it or just copy it.

import 'rehype-callout/css';
@import 'rehype-callout/css'; /* in css file @import */

prefix

to avoid css confilict

customize the prefix config option.
by default, {prefix:“callout”}.

output with config {prefix:"custom-prefix"} will like this
<blockquote data-custom-prefix="note">
<div class="custom-prefix-title">
<div class="custom-prefix-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<line x1="18" y1="2" x2="22" y2="6"></line>
<path d="M7.5 20.5 19 9l-4-4L3.5 16.5 2 22z"></path>
</svg></div>
<div class="custom-prefix-title-inner">This is a<strong>note</strong>callout.</div>
</div>
<div class="custom-prefix-content">
<p>你好!</p>
<h2>inner title</h2>
<p>This is the content!</p>
</div>
</blockquote>

dark mode

dark mode

surpport dark mode by css variables

[date-theme="dark"] [data-callout] {
...
}
last modified: 2024-08-10 21:45 +08:00