Skip to content

Markdown

Note: The markdown component is currently experimental and may undergo changes in future releases.

The markdown component renders Markdown content as Angular components. Use its options to configure extensions, code highlighting, and custom rendering behavior. Options can, and where possible should, be shared between multiple component instances.

Usage --

Basic usage

Create the options once and pass the same instance to each si-markdown component that needs the configuration. The component supports GitHub Flavored Markdown by default, including tables, task lists, strikethrough, and autolinked URLs.

import { Component, signal } from '@angular/core';
import { makeSiMarkdownOptions, SiMarkdownComponent } from '@siemens/element-ng/markdown';
import { siMarkdownMathKaTeX } from '@siemens/element-ng/markdown/extensions/katex';
import { siMarkdownMermaid } from '@siemens/element-ng/markdown/extensions/mermaid';
import { siMarkdownHighlightJs } from '@siemens/element-ng/markdown/hightlighter/highlightjs';
import remarkGemoji from 'remark-gemoji';

@Component({
  imports: [SiMarkdownComponent],
  template: ` <si-markdown [markdown]="markdown()" [options]="markdownOptions" /> `
})
export class MarkdownExampleComponent {
  protected readonly markdown = signal('# Release notes');
  protected readonly markdownOptions = makeSiMarkdownOptions()
    .setCodeHighlighter(siMarkdownHighlightJs({ autoDetectLanguage: true }))
    .installExtension(siMarkdownMathKaTeX())
    .installExtension(siMarkdownMermaid())
    .installUnifiedPlugin(remarkGemoji);
}

Code highlighting

Configure syntax highlighting for fenced code blocks with siMarkdownHighlightJs() and .setCodeHighlighter(). The highlighter includes JavaScript, TypeScript, JSON, CSS, SCSS, Bash, Python, and XML languages (also HTML) by default.

Use languageLoader to load other languages only when a code block requests them. The loader receives the language name from the fence and returns the corresponding Highlight.js language module. Return undefined for languages your application does not support.

import {
  siMarkdownHighlightJs,
  type HighlightJSLanguageImport
} from '@siemens/element-ng/markdown/hightlighter/highlightjs';

const highlightJsLanguageLoader = async (language: string): HighlightJSLanguageImport => {
  switch (language) {
    case 'c':
      return import('highlight.js/lib/languages/c');
    case 'cpp':
      return import('highlight.js/lib/languages/cpp');
    case 'yaml':
      return import('highlight.js/lib/languages/yaml');
    default:
      return undefined;
  }
};

protected readonly markdownOptions = makeSiMarkdownOptions().setCodeHighlighter(
  siMarkdownHighlightJs({ languageLoader: highlightJsLanguageLoader })
);

When autoDetectLanguage is enabled, Highlight.js can only detect languages that have already been registered; it does not invoke languageLoader. Eagerly register every language you want to auto-detect, following the built-in language registration used by the Highlight.js component:

import hljs from 'highlight.js/lib/core';
import langYaml from 'highlight.js/lib/languages/yaml';

hljs.registerLanguage('yaml', langYaml);

protected readonly markdownOptions = makeSiMarkdownOptions().setCodeHighlighter(
  siMarkdownHighlightJs({ autoDetectLanguage: true })
);

Extensions

The following rendering support is included in every Markdown component:

Rendering supportPurpose
GitHub Flavored MarkdownParses tables, task lists, strikethrough, and autolinked URLs.
Inline HTMLRenders sanitized inline HTML.
Code blocksRenders fenced code blocks without syntax highlighting.

Optional integrations are configured through SiMarkdownOptions:

IntegrationConfigurationPurpose
KaTeX.installExtension(siMarkdownMathKaTeX())Parses and renders inline and block LaTeX math expressions. It accepts optional remark-math parser and KaTeX rendering options.
Mermaid.installExtension(siMarkdownMermaid())Renders fenced code blocks declared as mermaid as diagrams. It accepts optional Mermaid configuration.
Highlight.js.setCodeHighlighter(siMarkdownHighlightJs())Adds syntax highlighting to fenced code blocks. It accepts Highlight.js options, including automatic language detection.
Gemojis.installUnifiedPlugin(remarkGemoji)Converts emoji shortcodes such as :rocket: to emoji.

You can also add a compatible unified or remark plugin with .installUnifiedPlugin(plugin, options). This is useful for syntax that is not covered by the Element integrations, such as emoji shortcodes.

Bundle size: KaTeX, Mermaid, Highlight.js, and additional unified plugins increase the application bundle size. Import and configure only the integrations your Markdown content requires.

Custom extension

An extension can install unified plugin(s) and associate the AST node types produced by that plugin with Angular renderer components. As an example, the following provides an alternative to render LaTeX math expressions. Instead of using KaTeX it uses @webc.site/math. This package is smaller and faster than KaTeX, but can only produce MathML (supported by all major browsers). It is distributed under the MulanPSL-2.0, an OSI approved liberal license.

import remarkMath, { type Options } from 'remark-math';

import { SiMarkdownExtension } from '../../si-markdown.types';
import { SiMarkdownMathComponent } from './si-markdown-math.component';

export const siMarkdownWebcSiteMath = (parseOptions?: Options): SiMarkdownExtension => {
  return {
    plugins: [{ plugin: remarkMath, options: parseOptions }],
    types: [
      { type: 'math', component: SiMarkdownMathComponent },
      { type: 'inlineMath', component: SiMarkdownMathComponent }
    ]
  };
};

The renderer implements SiMarkdownExtensionComponent. Element supplies the parsed node, its parent, and the options provided in the extension definition as signal inputs.

import { Component, computed, inject, input } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import mathml from '@webc.site/math';
import { Literal, type Node, type Parent } from 'mdast';

import { SiMarkdownExtensionComponent } from '../../si-markdown.types';

@Component({
  selector: 'si-markdown-math',
  template: '',
  host: {
    '[attr.data-line]': 'node().position?.start?.line',
    '[class.d-block]': 'displayMode()',
    '[innerHTML]': 'html()'
  }
})
export class SiMarkdownMathComponent implements SiMarkdownExtensionComponent {
  private readonly sanitizer = inject(DomSanitizer);

  readonly node = input.required<Node>();
  readonly parent = input.required<Parent>();
  readonly options = input<any>();

  protected readonly displayMode = computed(() => this.node().type === 'math');
  protected readonly html = computed(() => {
    const expr = (this.node() as Literal).value;
    const html = mathml(expr, this.displayMode());
    return this.sanitizer.bypassSecurityTrustHtml(html);
  });
}

Register the extension with the component options:

protected readonly markdownOptions = makeSiMarkdownOptions().installExtension(siMarkdownWebcSiteMath());

Code

SiMarkdownComponent API Documentation

selector
si-markdown

Component to display markdown text

This component is built using concepts from ngx-remark, namely using Angular templates to render the AST produced by remark .

Unlike ngx-remark , it features a configuration based approach of extensibility so that multiple instances of the component can be used with the same configuration, e.g. inside a chat component w/o repeating templates.

Input Properties

NameTypeDefaultDescription
citations
SiMarkdownCitation[]Citation metadata used to create citations.
debug
booleanfalseDebug mode. When true, unknown node types will be displayed along with the node as JSON.
markdown
string''The markdown text to transform and display
options
SiMarkdownOptionsOptions to control rendering. Can be shared across multiple instances.

Output Properties

NameTypeDescription
extensionEvent
{ data: any, name: string }Emitted by extension components.

Attributes and Methods

NameTypeDefaultDescription
(readonly) meta
Signal<SiMarkdownMetadata>...Gives access to metadata in extension components

Types Documentation

Citation metadata associated with a markdown response.
Properties
Optional source description.
description?: string from description
Identifier referenced by bracket notation, such as [source-1] .
identifier?: string
Source name displayed to the user.
name: string from name
Zero-based, end-exclusive source range of the citation reference in the markdown source.
position?: { endIndex: number, startIndex: number }
Optional source quote. Takes precedence over description .
quote?: string from quote
Source URL.
url: string from url
Options for the markdown renderer. This holds all configuration and allows installing extensions. A number of extensions are already ready to use and shipped with Element.

Example:
import { siMarkdownMathKaTeX } from '@siemens/element-ng/markdown/extensions/math';
import remarkGemoji from 'remark-gemoji';

protected markdownOptions = new SiMarkdownOptions()
  .installExtension(siMarkdownMathKaTeX())
  .installUnifiedPlugin(remarkGemoji);


<si-markdown [markdown]="markdownText()" [options]="markdownOptions" />
Constructor
() => {}
Properties
codeTypes: Map<string, TypeHandler> = ...
highlighter?: SiMarkdownHighlighter
plugins: PluginWithOptions[] = []
types: TypeHandler[] = []
Methods
Returns All code type handlers
getCodeTypeHandlers: () => Map<string, TypeHandler>
Returns The highlighter
getHighlighter: () => (SiMarkdownHighlighter | undefined)
Returns All type handlers
getTypeHandlers: () => TypeHandler[]
Installs a extension which can contain plugins, type handlers
Returns self for chaining
Parameters
The extension definition
extension: SiMarkdownExtension
Installs a plugin into the unified chain
Returns self for chaining
Parameters
The unified plugin
plugin: UnifiedPlugin
Options for the plugin
options?: any
Creates the unified processor with all plugins and options
Returns unified processor
Parameters
meta: SiMarkdownMetadata
Sets the code highlighter
Parameters
The highlighter
highlighter?: SiMarkdownHighlighter
Options passed to makeProcessor()
Properties
citations?: SiMarkdownCitation[]
Definition of a single source
Properties
Optional source description.
description?: string
Source name displayed to the user.
name: string
Optional source quote. Takes precedence over description .
quote?: string
Source URL.
url: string
AST node type handler
Properties
The component used to render the node
component: Type<SiMarkdownExtensionComponent> from component
Options passed to the component
options?: any from options
type of the AST node
type: string
Combination of unified plugin with options
Properties
Options passed during plugin registration
options?: any
The plugin
plugin: UnifiedPlugin
A combination of a component and options passed to it during run-time
Properties
The component used to render the node
component: Type<T>
Options passed to the component
options?: any
Interface an extension component must implement
Properties
Node to be rendered
node: InputSignal<Node>
Options passed to the component
options: InputSignal<any>
The parent node
parent: InputSignal<Parent>
Interface a code highlighter component must implement
Properties
The code to be highlighted
code: InputSignal<string>
The language
language: InputSignal<string>
Options passed to the component
options: InputSignal<any>
Function the highlighter can call to updated the displayed language
updateLanguage: InputSignal<(lang: string) => void>
Processor
import
imported from unified
import
imported from @types/mdast
(Omit<Root, "children"> & { children: ExtendedRootContent[], references: { definitions: Map<string, Definition>, footnoteDefinitions: Map<string, FootnoteDefinition> } })
Extended root with references
An extension to the si-markdown component
Properties
Special code type handlers to install
codeTypes?: TypeHandler[]
unified plugins to install
plugins?: PluginWithOptions[]
Type handlers to install
types?: TypeHandler[]
import
imported from @types/mdast
import
imported from @types/mdast
Plugin
import
imported from unified
Transformer
import
imported from unified
Preset
import
imported from unified
PluggableList
import
imported from unified
imported from @types/mdast
Extra node for collecting all footnotes
Properties
List of children.
children: FootnoteDefinition[]
Info from the ecosystem.
data?: Data from Parent.data
Position of a node in a source document.

Nodes that are generated (not in the original source document) must not have a position.

position?: Position from Parent.position
Node type.
type: "footnotes"
Container for one or more adjacent citation nodes.
Properties
children: Citation[]
Info from the ecosystem.
data?: Data from Node.data
Position of a node in a source document.

Nodes that are generated (not in the original source document) must not have a position.

position?: Position from Node.position
Node type.
type: "citations"
imported from @types/mdast
imported from @types/mdast
import
imported from @types/mdast
imported from @types/unist
Inline node that references an item in the source citation array.
Properties
citationIndex: number
Info from the ecosystem.
data?: Data from Node.data
Position of a node in a source document.

Nodes that are generated (not in the original source document) must not have a position.

position?: Position from Node.position
Text replaced by a position-based citation.
text?: string
Node type.
type: "citation"

Except where otherwise noted, content on this site is licensed under MIT License.