Quick start
From an empty Angular project to a rendered document with a live Angular component inside it.
Register the provider
provideMarkdown() returns EnvironmentProviders, so it goes in the providers array of your
application config.
import { ApplicationConfig } from '@angular/core';
import { provideMarkdown } from 'shikidown';
export const appConfig: ApplicationConfig = {
providers: [
provideMarkdown({
theme: { dark: 'github-dark', light: 'catppuccin-latte' },
}),
],
};Every option has a default, so an empty call works too. See Configuration for the full list.
Render a document
Import MarkdownComponent and give it some Markdown.
import { Component } from '@angular/core';
import { MarkdownComponent } from 'shikidown';
@Component({
selector: 'app-docs-page',
imports: [MarkdownComponent],
template: `<shikidown [content]="md" class="prose dark:prose-invert max-w-none" />`,
})
export class DocsPage {
readonly md = `# Hello
This is **shikidown**.
\`\`\`typescript
const answer: number = 42;
\`\`\`
`;
}The class lands on the host element. shikidown ships no styles of its own, so this is where you
attach your typography — see Styling and dark mode.
Put a component in the Markdown
Register a component against a selector, then write that selector in the document.
import { Component, input, numberAttribute, signal } from '@angular/core';
@Component({
selector: 'my-counter',
template: `<button (click)="count.set(count() + 1)">{{ label() }}: {{ count() }}</button>`,
})
export class CounterComponent {
readonly initialCount = input(0, { transform: numberAttribute });
readonly label = input('Clicks');
readonly count = signal(0);
constructor() {
this.count.set(this.initialCount());
}
}provideMarkdown({
components: { 'my-counter': CounterComponent },
});# My page
<my-counter initial-count="5" label="Votes"></my-counter>The rendered counter is a real Angular component: it has its own state, its own change detection,
and its inputs are fed from the HTML attributes. Note the kebab-case attribute mapping to the
camelCase input — the browser does that for you, and it is covered in
Embedding Angular components.
Turn on incremental rendering
If the document changes as the user types — an editor, a live preview — enable incremental rendering so only the edited block is re-processed.
provideMarkdown({
incrementalRendering: true,
});Unchanged blocks keep their DOM nodes, which means the counter above does not reset when you edit an unrelated paragraph. See Incremental rendering for how that works.