Skip to main content

Usage With Markdown #

Following this tutorial you will learn how to output Duet components from Markdown using the popular JavaScript library Marked.js.

Installation #

The package @duetds/marked offers a custom renderer for the most popular JavaScript Markdown library marked.js, so that it outputs Duet components like <duet-paragraph> rather than standard HTML tags like <p>.

As the first step, you will want to install this package. To do so, run the following command in your terminal:

npm install @duetds/marked

Usage #

For usage in vanilla JavaScript:

import marked from "marked"
import { createDuetMarkedRenderer } from "@duetds/marked"

const renderer = createDuetMarkedRenderer()
marked.use({ renderer })

console.log(marked("# hello duet!"))

Optionally, you can supply a function isExternalUrl which is used to determine whether a link should open in a new window or not:

import marked from "marked"
import { createDuetMarkedRenderer } from "@duetds/marked"

// the logic can be as simple or as complex as necessary
function isExternalUrl(url) {
return new URL(url).host !== "www.duetds.com"
}

const renderer = createDuetMarkedRenderer({ isExternalUrl })
marked.use({ renderer })

console.log(marked("[an external link](https://www.lahitapiola.fi)"))

Usage with Angular #

The @duetds/marked package can be integrated with ngx-markdown. In your app.module.ts file:

// 1. import these
import { createDuetMarkedRenderer } from "@duetds/marked";
import { MarkdownModule, MarkedRenderer, MarkedOptions } from "ngx-markdown";

// 2. define this function
export function markedOptionsFactory(): MarkedOptions {
return {
renderer: Object.assign(
new MarkedRenderer(),
createDuetMarkedRenderer()
),
};
}

// 3. configure the MarkdownModule to use our options factory
@NgModule({
imports: [
MarkdownModule.forRoot({
markedOptions: {
provide: MarkedOptions,
useFactory: markedOptionsFactory,
},
}),
],
})
export class AppModule {}

Then in a template, such as app.component.html, you can render markdown like so:

<!-- with string literal -->
<markdown ngPreserveWhitespaces># hello duet!</markdown>

<!-- binding to data -->
<markdown [data]="someComponentProperty" ngPreserveWhitespaces></markdown>

<!-- using pipes -->
<div>{{ someComponentProperty | markdown }}</div>

For more information, please read the ngx-markdown documentation.

Usage with React #

First you should create a Markdown component:

import React from "react"
import marked from "marked"
import { createDuetMarkedRenderer } from "@duetds/marked"

marked.use({ renderer: createDuetMarkedRenderer() })

// use React.memo to avoid re-renders if the markdown source hasn't changed
const Markdown = React.memo(function Markdown({ source }) {
return <div dangerouslySetInnerHTML={{ __html: marked(source) }} />
})

export default Markdown

Which can then be used like this:

import React from "react";
import ReactDOM from "react-dom"
import Markdown from "./Markdown"

ReactDOM.render(
<Markdown source="# hello duet!" />,
document.querySelector("#app")
);

Example #

If you have followed along with the above, then the following input:

# Hello world

This is a paragraph containing [a link](https://www.duetds.com/).

## Sub-heading

* Here
* Is
* A
* List

1. Here
1. Is
1. An
1. Ordered
1. List

Should result in the following output:

<duet-heading level="h1">Hello world</duet-heading>
<duet-paragraph>
This is a paragraph containing
<duet-link url="https://www.duetds.com/">a link</duet-link>.
</duet-paragraph>
<duet-heading level="h2">Sub-heading</duet-heading>
<ul class="duet-list">
<li>Here</li>
<li>Is</li>
<li>A</li>
<li>List</li>
</ul>
<ol class="duet-list">
<li>Here</li>
<li>Is</li>
<li>An</li>
<li>Ordered</li>
<li>List</li>
</ol>