A feature-rich Angular component for rendering Markdown content with syntax highlighting, Mermaid diagrams, collapsible sections, GitHub-style alerts, and SVG rendering.
npm install @memberjunction/ng-markdown
The Markdown component replaces ngx-markdown with a MemberJunction-native implementation. It uses marked for parsing, Prism.js for syntax highlighting, and Mermaid for diagram rendering. The module does not use forRoot() -- simply import MarkdownModule wherever needed.
flowchart LR
subgraph Input["Markdown Source"]
A["Raw Markdown String"]
end
subgraph Parser["Parsing Pipeline"]
B["marked parser"]
B --> C["marked-highlight (Prism.js)"]
B --> D["marked-alert (GitHub alerts)"]
B --> E["marked-smartypants (typography)"]
end
subgraph Render["Rendering"]
C --> F["Syntax-highlighted code blocks"]
D --> G["Alert blockquotes"]
B --> H["Mermaid diagrams"]
B --> I["SVG code blocks"]
end
A --> B
style Input fill:#2d6a9f,stroke:#1a4971,color:#fff
style Parser fill:#7c5295,stroke:#563a6b,color:#fff
style Render fill:#2d8659,stroke:#1a5c3a,color:#fff
import { MarkdownModule } from '@memberjunction/ng-markdown';
@NgModule({
imports: [MarkdownModule] // No forRoot() needed
})
export class YourModule {}
<mj-markdown [data]="markdownContent"></mj-markdown>
<mj-markdown
[data]="content"
[enableMermaid]="true"
[enableCollapsibleHeadings]="true"
[collapsibleHeadingLevel]="2"
[autoExpandLevels]="[2]"
[enableCodeCopy]="true"
[enableAlerts]="true"
[enableSmartypants]="true"
[enableSvgRenderer]="true"
[enableHtml]="false"
[mermaidTheme]="'default'"
(rendered)="onRendered($event)"
(headingClick)="onHeadingClick($event)"
(codeCopied)="onCodeCopied($event)">
</mj-markdown>
| Feature | Default | Description |
|---|---|---|
| Syntax highlighting | Enabled | Prism.js with Okaidia theme |
| Mermaid diagrams | Enabled | Render mermaid code blocks as diagrams |
| Math | Enabled | TeX ($…$ / \(…\) inline, $$…$$ / \[…\] display), typeset as MathML by KaTeX (loaded on first use), and MathML markup, including JATS-style <mml:math> |
| Code copy button | Enabled | Copy-to-clipboard on hover |
| GitHub-style alerts | Enabled | [!NOTE], [!TIP], [!WARNING] blockquotes |
| Smartypants typography | Enabled | Curly quotes, em/en dashes, ellipsis |
| SVG rendering | Enabled | Render SVG code blocks as images |
| Collapsible headings | Disabled | Expand/collapse heading sections |
| HTML passthrough | Disabled | Raw HTML rendering (security-sensitive) |
| JavaScript | Disabled | Allow JS in HTML (use only for trusted content) |
| Input | Type | Default | Description |
|---|---|---|---|
data |
string |
'' |
Markdown content to render |
enableHighlight |
boolean |
true |
Prism.js syntax highlighting |
enableMermaid |
boolean |
true |
Mermaid diagram rendering |
EnableMath |
boolean |
true |
TeX math, and keeping markdown out of MathML markup (<mml:math> needs it; unprefixed <math> renders either way, since the sanitizer allows MathML). Single dollars follow Pandoc's rule, so $5 and $10 stays text; \$ is a literal dollar. PascalCase only: unlike the older inputs above, it has no lowercase alias |
enableCodeCopy |
boolean |
true |
Copy button on code blocks |
enableCollapsibleHeadings |
boolean |
false |
Collapsible heading sections |
collapsibleHeadingLevel |
1-6 |
2 |
Heading level to start collapsing |
collapsibleDefaultExpanded |
boolean |
true |
Default expansion state |
autoExpandLevels |
number[] |
undefined |
Specific levels to auto-expand |
enableAlerts |
boolean |
true |
GitHub-style alerts |
enableSmartypants |
boolean |
true |
Typography improvements |
enableSvgRenderer |
boolean |
true |
SVG code block rendering |
enableHtml |
boolean |
false |
Raw HTML passthrough |
enableJavaScript |
boolean |
false |
Allow JS in HTML |
enableHeadingIds |
boolean |
true |
Generate heading IDs for anchors |
headingIdPrefix |
string |
'' |
Prefix for heading IDs |
enableLineNumbers |
boolean |
false |
Show line numbers in code blocks |
containerClass |
string |
'' |
Custom CSS class for container |
mermaidTheme |
string |
'default' |
Mermaid theme (default/dark/forest/neutral/base) |
sanitize |
boolean |
true |
Sanitize HTML output |
OpenLinksInNewTab |
boolean |
false |
Open rendered HTML links (external and relative/same-origin URLs, whether bare https://... autolinks or [text](url) links) in a new browser tab (target="_blank" with rel="noopener noreferrer"). In-page fragment links (#heading), mailto: / tel: / sms: links, and raw HTML links with an explicit target keep their behaviour. PascalCase only |
| Event | Type | Description |
|---|---|---|
rendered |
MarkdownRenderEvent |
Emitted when rendering completes |
headingClick |
HeadingInfo |
Emitted when a heading is clicked |
codeCopied |
string |
Emitted when code is copied to clipboard |
ImageClicked |
ImageClickedEventArgs |
Emitted when a rendered image (not one inside a link) is clicked or activated by keyboard; images react only while this is bound |
Tall images can be capped by the host with the --mj-markdown-image-max-height CSS custom property (unset: no cap), for example --mj-markdown-image-max-height: 360px on a chat column.
'ngx-markdown' to '@memberjunction/ng-markdown'forRoot() from module imports<markdown> to <mj-markdown>element property is preserved for backward compatibilitymarked -- Markdown parsermarked-alert -- GitHub-style alertsmarked-highlight -- Syntax highlighting integrationmarked-smartypants -- Typography improvementsprismjs -- Syntax highlightingmermaid -- Diagram renderingkatex -- TeX math typesetting (MathML output, so no KaTeX stylesheet or fonts are needed)