Render Angular Components in Markdown

RMAG news

This example demonstrates renderring of markdown in angular and also how to render angular components in markdown.

First, we will setup <markdown-render> component to render .md files. And then we will look how to render angular components.

Markdown Renderer

Install needed dependencies:

npm i highlight.js marked marked-highlight

Step 1: Create markdown-renderer/highlight-code-block.ts

This function will be used to highlight code in our markdown file

import highlightJs from highlight.js;

export function highlightCodeBlock(code: string, language: string | undefined) {
if (language) {
return highlightJs.highlight(code, {
language,
}).value;
}

return code;
}

Step 2: Create markdown-renderer/transform-markdown.ts

This function will be used to convert markdown to html.

import { marked } from marked;
import { markedHighlight } from marked-highlight;
import { highlightCodeBlock } from ./highlight-code-block;

marked.use(markedHighlight({ highlight: highlightCodeBlock }));

export const markdownToHtml = (content: string) => {
return marked(content);
};

Step 3: Create markdown-renderer/markdown.service.ts

This service will be used in the component to read .md file from local or external location and then convert it to html.

import { HttpClient } from @angular/common/http;
import { Injectable, inject } from @angular/core;
import { map } from rxjs;
import { markdownToHtml } from ./transform-markdown;

@Injectable({
providedIn: root,
})
export class MarkdownService {
private httpClient = inject(HttpClient);

htmlContent(src: string) {
return this.httpClient.get(src, { responseType: text }).pipe(
map((markdownContent) => {
return markdownToHtml(markdownContent);
})
);
}
}

Step 4: Create markdown-renderer/markdown-renderer.ts

Finally, this will be out component which we can use to render markdown files.

import { Component, ElementRef, effect, inject, input } from @angular/core;
import { MarkdownService } from ./markdown.service;
import { take } from rxjs;
import highlightJs from highlight.js;

@Component({
selector: markdown-renderer,
template: Loading document…,
standalone: true,
})
export class MarkdownRendererComponent {
src = input.required<string>();
textContent = ;

private _elementRef = inject<ElementRef>(ElementRef);

private markdownService = inject(MarkdownService);

constructor() {
effect(() => {
const src = this.src();
this.setDataFromSrc(src);
});
}

setDataFromSrc(src: string) {
this.markdownService
.htmlContent(src)
.pipe(take(1))
.subscribe((htmlContent) => {
this.updateDocument(htmlContent as string);
});
}

updateDocument(rawHTML: string) {
this._elementRef.nativeElement.innerHTML = rawHTML;
this.textContent = this._elementRef.nativeElement.textContent;
highlightJs.highlightAll();
}
}

Step 5: Provide HTTP

bootstrapApplication(App, {
providers: [
provideHttpClient(withFetch())
],
});

Step 6: Usage

Now, wherever we want to render markdown, we will simply use <markdown-renderer>:

import { Component } from @angular/core;
import { MarkdownRendererComponent } from ./markdown-renderer/markdown-renderer;

@Component({
selector: article,
standalone: true,
template: `<markdown-renderer src=”/assets/article.md”></markdown-renderer>`,
imports: [MarkdownRendererComponent],
})
export class ArticleComponent {}

Angular Components in Markdown

Install needed dependencies:

npm i @angular/elements

Step 1: Create custom-elements.service.ts

This service will used to convert angular components to custom elements, so that we can easily use angular components in in .md file.

import { inject, Injectable, Injector } from @angular/core;
import { createCustomElement } from @angular/elements;
import { SubscribeComponent } from ./components/subscribe;
import { CounterComponent } from ./components/counter;

@Injectable({ providedIn: root })
export class CustomElementsService {
private _injector = inject(Injector);

setupCustomElements() {
const subscribeElement = createCustomElement(SubscribeComponent, {
injector: this._injector,
});
customElements.define(subscribe-component, subscribeElement);

const counterElement = createCustomElement(CounterComponent, {
injector: this._injector,
});
customElements.define(counter-component, counterElement);
}
}

Step 2: Call setupCustomElements through APP_INITIALIZER

As we want custom elements present from the initialization, we will use APP_INITIALIZER.

bootstrapApplication(App, {
providers: [
provideHttpClient(withFetch()),
{
provide: APP_INITIALIZER,
useFactory: initializeCustomElements,
multi: true,
deps: [CustomElementsService],
},
],
});

Step 3: Usage

Finally, you can simply use your custom element in .md file it will render the angular component, like below:

<subscribe-component></subscribe-component>
<counter-component></counter-component>

Code

Please follow and like us:
Pin Share