Skip to main content

Documentation Index

Fetch the complete documentation index at: https://cometchat-22654f5b-release-flutter-v5-stable.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Overview

CometChatMarkdownRenderer converts a markdown string to sanitized HTML using a custom TypeScript parser — no third-party markdown library is required. It is used internally by CometChatAIAssistantMessageBubble (completed messages) and CometChatStreamMessageBubble (live streaming), but can be used standalone anywhere you need markdown rendering. Key capabilities:
  • Zero dependencies — custom CometChatMarkdownParser class; no marked, remark, or highlight.js
  • Streaming-safe — when streaming is true, incomplete syntax at the end of the text is rendered as plain text rather than dropped or throwing an error
  • XSS sanitization — all raw HTML in the input is escaped before markdown rules are applied; only the supported markdown constructs produce HTML elements
  • Code block copy — each fenced code block gets a copy button; state is tracked per-block as an independent WritableSignal<boolean>
  • Image click — clicking a rendered image emits imageClick with the image URL
  • Extensible parserCometChatMarkdownParser is exported from the public API so you can extend it with custom node types

Supported Markdown Constructs

SyntaxOutput
# Heading through ###### Heading<h1><h6>
**bold**<strong>
_italic_<em>
~~strikethrough~~<del>
`inline code`<code>
```lang\ncode\n```<pre><code class="language-{lang}">
> blockquote<blockquote>
1. item<ol><li>
- item or * item<ul><li>
Nested lists (up to 3 levels)Nested <ul> / <ol>
[text](url)<a target="_blank" rel="noopener noreferrer">
![alt](url)Clickable <img>
---<hr>
Two trailing spaces or \n\n<br> / paragraph
GFM tables | col | col |<table><thead><tbody>

Basic Usage

import { Component } from '@angular/core';
import { CometChatMarkdownRenderer } from '@cometchat/chat-uikit-angular';

@Component({
  selector: 'app-markdown-demo',
  standalone: true,
  imports: [CometChatMarkdownRenderer],
  template: `
    <cometchat-markdown-renderer
      [text]="markdownText"
    ></cometchat-markdown-renderer>
  `,
})
export class MarkdownDemoComponent {
  markdownText = `
## Hello World

Here is some **bold** text and _italic_ text.

\`\`\`typescript
const greeting = 'Hello, World!';
console.log(greeting);
\`\`\`

- Item one
- Item two
  - Nested item

[CometChat Docs](https://www.cometchat.com/docs)
  `;
}

Inputs

InputTypeDefaultDescription
textstringrequiredThe markdown string to parse and render
streamingbooleanfalseWhen true, tolerates incomplete syntax at the end of the string (for live streaming use cases)

Outputs

OutputPayloadDescription
imageClickstringEmitted with the image URL when a rendered image is clicked; use this to open CometChatFullScreenViewer

Streaming Mode

When rendering a live AI response, set streaming to true. The parser will render any incomplete markdown at the end of the string as plain text rather than dropping it or throwing an error. This prevents visual glitches as tokens arrive incrementally.
@Component({
  standalone: true,
  imports: [CometChatMarkdownRenderer],
  template: `
    <cometchat-markdown-renderer
      [text]="streamedText"
      [streaming]="true"
    ></cometchat-markdown-renderer>
  `,
})
export class StreamingBubbleComponent {
  streamedText = ''; // Updated on each text_message_content event
}

Image Click Handling

Wire imageClick to open the full-screen viewer:
import { Component } from '@angular/core';
import { CometChatMarkdownRenderer, CometChatUIEvents } from '@cometchat/chat-uikit-angular';

@Component({
  standalone: true,
  imports: [CometChatMarkdownRenderer],
  template: `
    <cometchat-markdown-renderer
      [text]="markdownText"
      (imageClick)="onImageClick($event)"
    ></cometchat-markdown-renderer>
  `,
})
export class MarkdownWithImagesComponent {
  markdownText = '![Screenshot](https://example.com/screenshot.png)';

  onImageClick(imageUrl: string): void {
    CometChatUIEvents.ccShowDialog.next({ child: imageUrl });
  }
}

Extending the Parser

CometChatMarkdownParser is exported from the public API. Extend it to add custom node types — for example, a chart block or a video embed — without modifying the renderer component.
import {
  CometChatMarkdownParser,
  MarkdownNode,
} from '@cometchat/chat-uikit-angular';

export class MyMarkdownParser extends CometChatMarkdownParser {
  override parse(text: string, streaming?: boolean): MarkdownNode[] {
    // Pre-process custom syntax before passing to the base parser
    const preprocessed = text.replace(
      /:::chart\n([\s\S]*?):::/g,
      (_match, data) => `\`\`\`chart\n${data}\n\`\`\``
    );
    return super.parse(preprocessed, streaming);
  }
}
Then provide your custom parser to the renderer by subclassing CometChatMarkdownRenderer or by rendering the HTML yourself using the parser directly:
import { Component, computed, input } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { MyMarkdownParser } from './my-markdown-parser';

@Component({
  selector: 'app-custom-renderer',
  standalone: true,
  template: `<div [innerHTML]="html()"></div>`,
})
export class CustomRendererComponent {
  text = input.required<string>();

  private parser = new MyMarkdownParser();
  private sanitizer = inject(DomSanitizer);

  html = computed(() => {
    const nodes = this.parser.parse(this.text());
    // Walk nodes and produce HTML string, then sanitize
    const raw = nodesToHtml(nodes); // your own walker
    return this.sanitizer.bypassSecurityTrustHtml(raw);
  });
}

BEM Class Reference

All rendered elements carry BEM class names prefixed with cometchat-markdown-renderer. Use these to apply custom styles:
ElementClass
Headingscometchat-markdown-renderer__heading, cometchat-markdown-renderer__heading--1--6
Paragraphcometchat-markdown-renderer__paragraph
Boldcometchat-markdown-renderer__bold
Italiccometchat-markdown-renderer__italic
Strikethroughcometchat-markdown-renderer__strikethrough
Inline codecometchat-markdown-renderer__inline-code
Code block wrappercometchat-markdown-renderer__code-block
Copy buttoncometchat-markdown-renderer__code-copy-btn
Blockquotecometchat-markdown-renderer__blockquote
Ordered listcometchat-markdown-renderer__ordered-list
Unordered listcometchat-markdown-renderer__unordered-list
List itemcometchat-markdown-renderer__list-item
Linkcometchat-markdown-renderer__link
Imagecometchat-markdown-renderer__image
Horizontal rulecometchat-markdown-renderer__hr
Tablecometchat-markdown-renderer__table
Table headcometchat-markdown-renderer__table-head
Table header cellcometchat-markdown-renderer__table-header-cell
Table bodycometchat-markdown-renderer__table-body
Table rowcometchat-markdown-renderer__table-row
Table cellcometchat-markdown-renderer__table-cell

Example: Custom Code Block Styling

cometchat-markdown-renderer .cometchat-markdown-renderer__code-block {
  background: var(--cometchat-background-color-03);
  border-radius: var(--cometchat-radius-2);
  padding: var(--cometchat-spacing-3);
  position: relative;
}

cometchat-markdown-renderer .cometchat-markdown-renderer__code-copy-btn {
  position: absolute;
  top: var(--cometchat-spacing-2);
  right: var(--cometchat-spacing-2);
  background: var(--cometchat-primary-color);
  color: #fff;
  border: none;
  border-radius: var(--cometchat-radius-1);
  padding: 2px 8px;
  cursor: pointer;
  font-size: 12px;
}

Localization Keys

KeyDefault (en-us)
ai_assistant_chat_code_copied”Copied!”
Override via CometChatLocalize.updateKeys():
import { CometChatLocalize } from '@cometchat/chat-uikit-angular';

CometChatLocalize.updateKeys('en', {
  ai_assistant_chat_code_copied: 'Copied to clipboard!',
});