MarkdownPipe
A pipe returning Signal<SafeHtml>, for when you need the HTML inside a template you already control.
MarkdownPipe renders Markdown to SafeHtml you can bind wherever you like. Reach for it when
<shikidown> would be one wrapper too many — inside a card you already lay out, a table cell, a
tooltip.
import { MarkdownPipe } from 'shikidown';
@Component({
imports: [MarkdownPipe],
template: `<div [innerHTML]="(md | markdown)()"></div>`,
})
export class MyComponent {
readonly md = '# Hello from the pipe';
}It returns a signal, not a string
Rendering is asynchronous — Shiki is loaded on demand — so the pipe returns a
Signal<SafeHtml> rather than the HTML itself. Call it in the template:
<!-- Correct -->
<div [innerHTML]="(md | markdown)()"></div>
<!-- Wrong: binds the signal object -->
<div [innerHTML]="md | markdown"></div>The signal starts as empty HTML and fills in when parsing resolves. To avoid an empty wrapper in
the meantime, bind through @let:
@let html = (md | markdown)();
@if (html) {
<div [innerHTML]="html"></div>
}Signature
transform(content: string | null | undefined): Signal<SafeHtml>null and undefined yield an already-resolved signal holding empty HTML — no parse is attempted.
Error handling
A parse failure is logged as [shikidown] MarkdownPipe: failed to parse content and the signal
falls back to empty HTML. Unlike MarkdownComponent, the pipe
has no error state to display: if you need one, render through the component instead.
Limitations
The pipe does not support incremental rendering.
incrementalRendering: true in provideMarkdown() has no effect here — every change re-parses
the whole document and replaces the whole DOM subtree, which resets the state of any embedded
component.
For a live editor, or any document that changes as the user types, use
MarkdownComponent.
Embedded components themselves do work: selectors registered through provideMarkdown() are
already defined when the pipe's output reaches the DOM. What the pipe has no equivalent for is the
[components] and [componentModules] inputs — there is no instance to attach them to, so
per-page registration must go through
registerComponentModules() yourself.
Content security
As with the component, the HTML is passed through bypassSecurityTrustHtml. Treat the Markdown
source as trusted input — see
Content security.