Skip to main content

Goal

By the end of this guide you will have a text color formatter, working end to end:
  • Composer: a toolbar button inserts a color token. The composer tints the token in that color as you type.
  • Send: the token is stored on the message as plain text, {color:#e5484d}text{/color}.
  • Display: the token renders as colored text in message bubbles, the thread header, pinned messages, and message information.
Each step below explains one part of the formatter with an excerpt. The complete code at the end is ready to drop into your app.
For the full CometChatTextFormatter API, see the Formatter API Reference at the end of this page. For the built-in formatters, see the Mentions, URL, and Hashtag guides.

Prerequisites

  • Completed the Integration Guide
  • A chat screen using cometchat-message-list and cometchat-message-composer
  • The rich-text composer enabled ([enableRichText]="true", [hideRichTextToolbar]="false") — the toolbar button lives in its toolbar

How It Works

A formatter has two jobs here, and ColorFormatter does both: The rich-text composer re-runs your formatters shortly after typing stops. It wraps each match in a span and copies the class from the span your format() returns, so the token is tinted in place. The token itself stays visible in the composer; it becomes plain colored text once it is sent and rendered.

Step 1: Token and Display

The token is plain text, so it survives storage and delivery unchanged. format() turns it into a span that carries the color as a CSS class. File: src/app/formatters/color-formatter.ts (excerpt)
format() must store originalText, set formattedText, and return the formatted string — the pipeline reads those fields. Keep it fast: it runs on every text message render.
Formatters run in priority order, lowest first. The built-in URL formatter runs at 10, mentions at 20, and markdown at 30. At 60, the color token is replaced after the built-in formatters have rendered inside it.

Step 2: Style the Colors

Each color is a CSS class, not an inline style. Angular sanitizes HTML bound through [innerHTML] and removes style attributes, so an inline color would never reach the message bubble. Classes survive, so define one per color your button offers. The spans are rendered inside the UI Kit’s components, so put the rules in your global stylesheet, not in a component’s encapsulated styles. File: src/styles.css
A token whose color has no matching class still renders, just in the default text color.

Step 3: The Toolbar Button

The composer renders toolbarTrailingView at the end of the rich-text toolbar, after the built-in groups and an automatically inserted separator. Its template context carries the composer, so a button can write into the editor with insertTextIntoRichTextEditor(). File: src/app/chat/chat.component.html (excerpt)
(mousedown)="$event.preventDefault()" keeps focus in the editor. Without it, clicking the button moves focus out of the editor before your handler runs.
Offer only the colors you defined classes for in Step 2.

Step 4: Wire It Into the Composer

Pass the button to toolbarTrailingView and the formatter to textFormatters. The toolbar — and therefore the trailing view — renders only while the rich-text editor and its toolbar are enabled. File: src/app/chat/chat.component.html
Passing textFormatters replaces the built-in formatters on that component — it does not add to them. Include the built-ins in the list, or markdown, links, and mentions stop rendering:

Step 5: Register It on Every Surface

A formatter only applies where it is registered. If a surface doesn’t have it, readers see the raw {color:…} token there. These components color the token: To set one list app-wide instead of per component, use textFormatters in Global Configuration — every component falls back to it when its own input is unset: File: src/app/app.config.ts (excerpt)
A thread panel has its own message list and composer, so register the formatter there too — or rely on the global configuration.

Complete Code

Formatter API Reference

Formatter output is always sanitized before it is rendered — there is no way to bypass sanitization. Make sure your HTML is sanitizer-compatible: use a <span> with CSS classes rather than inline styles.
Optionally override to conditionally skip formatting.

Next Steps