Installation
Packages to install, peer dependencies to satisfy, and the optional mermaid entry point.
Install
npm install shikidown shiki markdown-it @angular/elementsshiki and markdown-it are peer dependencies rather than dependencies: shikidown does not pin
their versions, and you get exactly one copy of each in your bundle.
@angular/elements is listed here because ng new does not install it, even though it ships with
Angular — see the note under Peer dependencies.
markdown-it v15 ships its own type definitions. On v14 they live in a separate package:
npm install --save-dev @types/markdown-it # v14 onlyPeer dependencies
| Package | Version | Required |
|---|---|---|
@angular/core | >=22.0.0 | Yes |
@angular/common | >=22.0.0 | Yes |
@angular/elements | >=22.0.0 | Yes |
@angular/platform-browser | >=22.0.0 | Yes |
markdown-it | >=14.0.0 | Yes |
shiki | >=4.4.3 | Yes |
mermaid | >=11.0.0 | Optional |
@angular/core, @angular/common and @angular/platform-browser are already present in any
Angular 22 application, so in practice the new installs are shiki, markdown-it and
@angular/elements.
@angular/elements is what turns your components into Custom Elements, and it is required,
not optional. It ships as part of Angular but ng new does not add it to package.json, so it is
usually missing. provideMarkdown() imports createCustomElement from it directly — without the
package the build fails on an unresolved import, before any of your own code runs.
TypeScript configuration
shiki >=4.4 declares [Symbol.dispose]() on its highlighter. That symbol is not part of the
ES2022 library that ng new configures, so the build fails before it reaches your own code:
TS2550: Property 'dispose' does not exist on type 'SymbolConstructor'.Add ESNext.Disposable to lib:
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable", "ESNext.Disposable"]
}
}Setting "target": "esnext" fixes it too — the implied library includes the symbol. Naming
ESNext.Disposable is narrower: it enables the one missing API rather than every
proposal-stage one, and it does not shift meaning when you upgrade TypeScript.
The mermaid entry point
mermaid is heavy, and most documents never contain a diagram. It is therefore an optional peer
dependency reached only through a secondary entry point:
npm install mermaidimport { MermaidDirective } from 'shikidown/mermaid';If you never import from shikidown/mermaid, mermaid never enters your dependency graph — and
fenced ```mermaid blocks simply stay rendered as code. See Mermaid diagrams.
Verifying the install
import { provideMarkdown } from 'shikidown';
export const appConfig: ApplicationConfig = {
providers: [provideMarkdown()],
};import { MarkdownComponent } from 'shikidown';
@Component({
imports: [MarkdownComponent],
template: `<shikidown content="# It works" />`,
})
export class SmokeTest {}provideMarkdown() is optional — the library falls back to its defaults when the configuration
token is absent. Calling it with no arguments, as above, is equivalent to not calling it at all;
it is shown here because that is where you will add options next.
Server-side rendering
shikidown is SSR-safe, with one caveat worth stating plainly: Shiki is only loaded in the
browser. On the server, code fences are rendered as plain, unhighlighted <pre><code> blocks,
and no Custom Element is defined. Highlighting appears once the client takes over.