Skip to content

Quick start

A page rendering real components, in three files.

Three files, and a page that renders Markdown with a working component in it.

1. A component to use

Nothing special: an ordinary Angular component.

ts
import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';
 
@Component({
  selector: 'app-button',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<button type="button" (click)="clicked.emit()"><ng-content /></button>`,
})
export class AppButton {
  readonly variant = input<'primary' | 'secondary'>('secondary');
  readonly clicked = output<void>();
}

2. The content

home.page.md, beside the class that will render it:

md
## Hello Blasdoc
 
This is **Markdown**, and the button below is a real component.
 
<app-button variant="primary" (clicked)="bump()">
  Pressed {{ count }} times
</app-button>

3. The page

ts
import { Component } from '@angular/core';
import { AppButton } from './app-button';
import templateMD from './home.page.md';
 
@Component({
  selector: 'app-home-page',
  templateMD,
  components: [AppButton],
})
export class HomePage {
  count = 0;
  bump(): void { this.count++; }
}

That is the whole setup. The class is the binding context: {{ count }} reads that field and (clicked)="bump()" calls that method.

Try it

The button below is running on this page, bound to this page's own state.

Without a page

When the Markdown arrives at runtime — an HTTP response, a CMS payload, a textarea — render the string directly:

ts
import { BlasdocContentComponent } from '@blasdoc/angular';
 
@Component({
  imports: [BlasdocContentComponent],
  template: `<blasdoc-content [source]="markdown" [context]="this" />`,
})
export class Viewer {
  markdown = '# Loaded at runtime';
}
  • Markdown — everything Blasdoc renders.

  • Bindings — the four Angular channels.

  • Pages — templateMD, and the two alternatives.