A rehype plugin to extend blockquote syntax to make it simple to mention/cite sources in a semantically correct way.
This package is a unified (rehype) plugin to extend blockquote syntax to allow simple citation/mention of source from which the quote originates conforming to semantic HTML standards
This project is useful if you want to have a simple syntax for citations in your blockquotes.
In markdown we can create blockquotes such as:
> We cannot solve our problems with the same thinking we used when we created them.
But often times, it may be desireable to include a reference to the person that mentioned that quote.
We might think to use the <cite>
element:
> We cannot solve our problems with the same thinking we used when we created them.
> -- <cite>Albert Einstein</cite>
But that is semantically incorrect! A <cite>
element should refer to work and not people. (e.g. instagram post, book, article)
Additionally, putting a <cite>
element within a <blockquote>
is forbidden by the HTML spec because it would make the citation a part of the quote.
So another solution could be something like this:
> We cannot solve our problems with the same thinking we used when we created them.
-- Albert Einstein
But that feels wrong, because it would render in the following way:
<blockquote>
<p>
We cannot solve our problems with the same thinking we used when we created
them.
</p>
</blockquote>
<p>-- Albert Einstein</p>
If we want to style them together we would have to wrap them within a parent element.
But there is a different approach, using the <figure>
element we can create a more semantic version.
This plugin does just that.
For instance, by turning the following syntax:
> We cannot solve our problems with the same thinking we used when we created them.
>
> @ Albert Einstein
Into this:
<figure data-blockquote-container="">
<blockquote data-blockquote-content="">
<p>
We cannot solve our problems with the same thinking we used when we created
them.
</p>
</blockquote>
<figcaption data-blockquote-credit="">
<p>Albert Einstein</p>
</figcaption>
</figure>
Then we can easily style the blockquote and the caption however we want to using CSS
[data-blockquote-container] {
display: flex;
flex-direction: column;
flex-gap: 8px;
}
[data-blockquote-credit]::before {
content: "- ";
}
Or even replace with our own custom component (e.g. if we were using MDX)
export const mdxComponents: MDXComponents = {
figure: ({ children, ...rest }) => {
if (rest["data-blockquote-container"] === "") {
// OK, we are only targeting the semantic blockquote
return <MyAwesomeComponent />
}
// do nothing to non semantic-blockquotes
return <figure {...rest}>{children}</figure>
}
};
Install with your package manager:
npm install rehype-semantic-blockquotes
pnpm add rehype-semantic-blockquotes
bun add rehype-semantic-blockquotes
deno add rehype-semantic-blockquotes
Say we have the following file example.js
:
import rehypeFormat from "rehype-format";
import rehypeSemanticBlockquotes from "rehype-semantic-blockquotes";
import rehypeStringify from "rehype-stringify";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import { unified } from "unified";
const markdown = `
> Better to admit you walked through the wrong door than spend your life in the wrong room.
>
> @ [Josh Davis](https://somewhere.com)
`;
const html = String(
await unified()
.use(remarkParse) // parse markdown
.use(remarkRehype) // convert markdown syntax tree into HTML syntax tree
.use(rehypeSemanticBlockquotes) // apply the plugin
.use(rehypeStringify) // convert HTML syntax tree into HTML
.use(rehypeFormat) // format HTML by adding insignificant whitespace
.process(markdown)
);
console.log(html);
...then running node example.js
yields:
<figure data-blockquote-container="">
<blockquote data-blockquote-content="">
<p>
Better to admit you walked through the wrong door than spend your life in
the wrong room.
</p>
</blockquote>
<figcaption data-blockquote-credit="">
<p><a href="https://somewhere.com">Josh Davis</a></p>
</figcaption>
</figure>
This package exports no identifiers. The default export is rehypeSemanticBlockquotes
.
Adds syntax @
which places the contents in the @
into the <figcaption>
element
The attributes (data-blockquote-figure
, etc.) are fully customizable. The plugin takes a parameter, opts
with the following defaults:
{
figure: "dataBlockquoteContaienr", // HTML attribute: data-blockquote-container
blockquote: "dataBlockquoteContent", // HTML attribute: data-blockquote-content
figcaption: "dataBlockquoteCredit", // HTML attribute: data-blockquote-credit
syntax: "@ ",
};
Note
Even though we use camelCase here, it will output as kebab-case
See: https://github.com/syntax-tree/hast#propertyname
Transform (Transformer
).
In the MD blockquote, if the last line starts with an @
and the line before is an empty line then the transformation will take place. Otherwise we will just get a regular <blockquote>
, the plugin won't take effect.
For example these snippets will not be affected by the plugin:
> We cannot solve our problems with the same thinking we used when we created them.
> We cannot solve our problems with the same thinking we used when we created them.
> @ Albert Einstein
> We cannot solve our problems with the same thinking we used when we created them.
>
> **@ Albert Einstein**
But these would:
> We cannot solve our problems with the same thinking we used when we created them.
>
> @ Albert Einstein
> We cannot solve our problems with the same thinking we used when we created them.
>
> @ **Albert Einstein**
MIT © Nikita Revenco