Render Angular Components in Markdown
Tags: angular, markdown, markedjs, highlightjs
Published: 2024-07-05 21:46:54

---
title: Render Angular Components in Markdown
published: true
description: 
tags: angular,markdown,markedjs,highlightjs
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rz5fcawiy5rrf8vyp5sb.png
---

> 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:

```bash
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

```ts
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.

```ts
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.

```ts
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.

```ts
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

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

### Step 6: Usage

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

```ts
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:

```bash
npm i @angular/elements
```

### Step 1: Create `custom-elements.service.ts`

This service will used to convert angular components to [custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements), so that we can easily use angular components in in `.md` file.

```ts
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`.

```ts
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:

```md
<subscribe-component></subscribe-component>
<counter-component></counter-component>
```

## Code

{% embed https://stackblitz.com/edit/stackblitz-starters-rgrpl6?file=src%2Fassets%2Farticle.md %}

## Support free content creation

Even though the courses and articles are available at no cost, your support in my endeavor to deliver top-notch educational content would be highly valued. Your decision to contribute aids me in persistently improving the course, creating additional resources, and maintaining the accessibility of these materials for all. I'm grateful for your consideration to contribute and make a meaningful difference!

[![🙏 Support free content creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/85uoalkeh2bfmz3b7yz1.png)](https://donate.stripe.com/00g17jgeYb1d2SA7sw?utm_source=devto)