This is a remark plugin that allows the usage of liquid tags.
This idea came from the usage of liquid tags in dev.to (DEV COMMUNITY) platform for embedding services in markdowns. This documented page shows their idea behind liquid tags and the tags available.
Liquid tags are special elements to use in markdown. They are custom embeds that are added via a {% %} syntax. Liquid is a templating language developed by Shopify.
npm install remark-react-liquid-tagThe plugin follows the unified ecosystem.
Here is an example using react-markdown to render markdown in React.
import React from 'react';
import Markdown from 'react-markdown';
import remarkReactLiquidTag, { RemarkReactLiquidTagProps } from 'remark-react-liquid-tag';
const LiquidTag: React.FC<RemarkReactLiquidTagProps> = (props) => {
switch (props.type) {
case 'youtube':
return (
<iframe
width="560"
height="315"
src={`https://www.youtube.com/embed/${props.url}`}
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
);
default:
return null;
}
};
const markdown = `
# Hello World
This is an example youtube video:
{% youtube dQw4w9WgXcQ %}
`;
export function App() {
return (
<Markdown
remarkPlugins={[
[remarkReactLiquidTag, { component: LiquidTag }],
]}
>
{markdown}
</Markdown>
);
}Here is an example using rehype-react to render the markdown in React.
import * as prod from 'react/jsx-runtime';
import { renderToString } from 'react-dom/server';
import rehypeReact from 'rehype-react';
import remarkParse from 'remark-parse';
import remarkToRehype from 'remark-rehype';
import { unified } from 'unified';
import remarkReactLiquidTag, { RemarkReactLiquidTagProps } from 'remark-react-liquid-tag';
const LiquidTag: React.FC<RemarkReactLiquidTagProps> = (props) => {
switch (props.type) {
case 'youtube':
return (
<iframe
width="560"
height="315"
src={`https://www.youtube.com/embed/${props.url}`}
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
);
default:
return null;
}
}
const markdown = `
# Hello World
This is an example youtube video:
{% youtube dQw4w9WgXcQ %}
This is a unsupported tag:
{% unsupported_tag %}
`;
const { result } = unified()
.use(remarkParse)
.use(remarkReactLiquidTag, {
component: LiquidTag,
})
.use(remarkToRehype)
.use(rehypeReact, prod)
.processSync(markdown);
// ...component: React component to render the liquid tag. It receives the following props:type: The type of the liquid tag (e.g.,youtube).url: The main value/url of the liquid tag.options: Key-value pairs of additional options passed in the tag (e.g.,{% type url key=value %}).config: Configuration specific to this tag type, passed via theconfigoption.
config: An object where keys are tag types and values are configuration objects passed to the component.
const { result } = unified()
.use(remarkParse)
.use(remarkReactLiquidTag, {
component: MyComponent,
config: {
youtube: {
autoplay: true
}
}
})
.use(remarkToRehype)
.use(rehypeReact, prod)
.processSync('{% youtube dQw4w9WgXcQ theme=dark %}');In this case, MyComponent will receive:
type:'youtube'url:'dQw4w9WgXcQ'options:{ theme: 'dark' }config:{ autoplay: true }
The plugin is written in TypeScript and exports types for your components.
import { RemarkReactLiquidTagProps } from 'remark-react-liquid-tag';
type MyYoutubeConfig = {
autoplay: boolean;
};
type MyYoutubeOptions = {
theme: string;
};
const MyComponent: React.FC<RemarkReactLiquidTagProps<MyYoutubeOptions, MyYoutubeConfig>> = (props) => {
// ...
};