Install remark-directive
mainInstall remark-directive via npm for Node.js (version 16+). This package is ESM only.
For Deno or browser usage, use esm.sh.
npm install remark-directiverepository·main·Indexed 19 days ago
https://github.com/remarkjs/remark-directiveA remark plugin that adds support for the generic directives proposal, allowing custom syntax such as :cite[], ::youtube[], or :::note[] in Markdown. It parses directive syntax into the MDAST syntax tree (containerDirective, leafDirective, and textDirective) but requires a custom remark plugin to transform these nodes into HTML elements.
Install remark-directive via npm for Node.js (version 16+). This package is ESM only.
For Deno or browser usage, use esm.sh.
npm install remark-directiveTo support generic directives in your markdown processing pipeline, include remarkDirective in your unified() chain.
Note that remark-directive only parses the syntax into the syntax tree (MDAST). It does not automatically convert directives into HTML. You must write a custom remark plugin to transform the directive nodes (e.g., containerDirective, leafDirective, or textDirective) into HTML elements by setting node.data.hName and node.data.hProperties.
import {unified} from 'unified'
import remarkParse from 'remark-parse'
import remarkDirective from 'remark-directive'
import remarkRehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify'
const file = await unified()
.use(remarkParse)
.use(remarkDirective)
.use(myRemarkPlugin) // Your custom transformation plugin
.use(remarkRehype)
.use(rehypeStringify)
.process(await read('example.md'))The remarkDirective plugin accepts an optional options object to control how directives are parsed and serialized.
| Field | Type | Default | Description |
|---|---|---|---|
collapseEmptyAttributes | boolean | true | Collapse empty attributes: get title instead of title="" |
preferShortcut | boolean | true | Prefer # and . shortcuts for id and class |
preferUnquoted | boolean | false | Leave attributes unquoted if that results in less bytes |
quoteSmart | boolean | false | Use the other quote if that results in less bytes |
quote | '"' or '"' | (from remark-stringify) | Preferred quote to use around attribute values |
You can create a plugin to transform a custom ::youtube leaf directive into an HTML <iframe>. The directive syntax used is ::youtube[Label]{#id}.
In the plugin, check for node.name === 'youtube', extract the id from node.attributes, and set node.data.hName to 'iframe' and node.data.hProperties to the iframe attributes.
import {visit} from 'unist-util-visit'
function myRemarkPlugin() {
return (tree, file) => {
visit(tree, function (node) {
if (node.type !== 'containerDirective' &&
node.type !== 'leafDirective' &&
node.type !== 'textDirective') return
if (node.name !== 'youtube') return
const data = node.data || (node.data = {})
const attributes = node.attributes || {}
const id = attributes.id
if (node.type === 'textDirective') {
file.fail('Unexpected `:youtube` text directive, use two colons for a leaf directive', node)
}
if (!id) {
file.fail('Unexpected missing `id` on `youtube` directive', node)
}
data.hName = 'iframe'
data.hProperties = {
src: 'https://www.youtube.com/embed/' + id,
width: 200,
height: 200,
frameBorder: 0,
allow: 'picture-in-picture',
allowFullScreen: true
}
})
}
}You can use directives to create styled callouts or admonitions (e.g., :::note{.warning}).
In your plugin, check for the directive name (e.g., note). Set node.data.hName to 'div' for container/leaf directives, or 'span' for text directives. Pass the attributes through to node.data.hProperties to ensure classes and IDs are applied correctly.
import {h} from 'hastscript'
import {visit} from 'unist-util-visit'
function myRemarkPlugin() {
return (tree) => {
visit(tree, (node) => {
if (
node.type === 'containerDirective' ||
node.type === 'leafDirective' ||
node.type === 'textDirective'
) {
if (node.name !== 'note') return
const data = node.data || (node.data = {})
const tagName = node.type === 'textDirective' ? 'span' : 'div'
data.hName = tagName
data.hProperties = h(tagName, node.attributes || {}).properties
}
})
}
}If you are working with the syntax tree in TypeScript, you can register the new directive node types with @types/mdast by adding a reference. This allows node to be recognized as one of the directive node types within unist-util-visit loops.
/**
* @import {} from 'mdast-util-directive'
* @import {} from 'mdast'
*/
import {visit} from 'unist-util-visit'
function myRemarkPlugin() {
return (tree) => {
visit(tree, function (node) {
// `node` can now be one of the nodes for directives.
console.log(node)
})
}
}To use remark-directive in a unified or remark pipeline, import the default export and pass it to .use(). This plugin enables support for directive syntax (like :name[label]{attr=val}) in your Markdown processing pipeline.
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkDirective from 'remark-directive'
import remarkStringify from 'remark-stringify'
// Example pipeline setup
const processor = unified()
.use(remarkParse)
.use(remarkDirective)
.use(remarkStringify)import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkDirective from 'remark-directive'
import remarkStringify from 'remark-stringify'
const processor = unified()
.use(remarkParse)
.use(remarkDirective)
.use(remarkStringify)To add support for generic directives in your markdown processing pipeline, use remarkDirective as a plugin with unified().use().
Important Note: This plugin only adds support for the directive syntax (parsing and stringifying). It does not handle the logic or transformation of the directives themselves. To perform actions based on specific directives (e.g., turning a :youtube directive into an iframe), you must create and use your own custom plugin to traverse the resulting AST.
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkDirective from 'remark-directive'
const processor = unified()
.use(remarkParse)
.use(remarkDirective)
// Now the processor can parse directive syntax into the AST