Mobile Development 11 min read

Text Component and Rich Text Handling in HarmonyOS: Styling, Emoji Integration, and Custom Keyboard

The article explains HarmonyOS’s Text component—showing basic usage, method‑chained styling, and mixed Span/ImageSpan content—then details an emoji workflow using a JSON mapping and regex to split text into model arrays, and demonstrates RichEditor with a custom keyboard for inserting and managing emoji spans.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Text Component and Rich Text Handling in HarmonyOS: Styling, Emoji Integration, and Custom Keyboard

The article introduces the Text component in HarmonyOS, showing its basic usage similar to other languages by directly passing a string, e.g., Text('I am a piece of text') .

It demonstrates how to style text using method chaining, including width, overflow handling, maximum lines, font size, border, and padding:

Text('I am an extra long text, the overflow part shows an ellipsis.')
  .width(250)
  .textOverflow({ overflow: TextOverflow.Ellipsis })
  .maxLines(1)
  .fontSize(12)
  .border({ width: 1 })
  .padding(10)

The Text component can also act as a container for Span and ImageSpan elements, allowing mixed‑style text and inline images. An example shows several Span objects with different colors, decorations, and font styles, together with ImageSpan that displays local or network images.

Text() {
  Span('I am Span1,').fontSize(16).fontColor(Color.Grey)
    .decoration({ type: TextDecorationType.LineThrough, color: Color.Red })
  Span('I am Span2').fontColor(Color.Blue).fontSize(16)
    .fontStyle(FontStyle.Italic)
    .decoration({ type: TextDecorationType.Underline, color: Color.Black })
  Span(', I am Span3').fontSize(16).fontColor(Color.Grey)
    .decoration({ type: TextDecorationType.Overline, color: Color.Green })
}.borderWidth(1)
 .padding(10)

To automatically match emoji images in dynamic text, the article explains a workflow:

Maintain an emoji configuration table (JSON) that maps keywords such as "[微笑]" to image names.

When backend data contains these keywords, use a regular expression built from all keywords to split the text into plain strings and emoji tokens.

Convert the split result into a model array where each element records the content, type (Text or Emoji), and associated resource.

Example of the configuration table:

{"imageName":"icon_emotion_1","description":"[微笑]","id":44},{"imageName":"icon_emotion_2","description":"[嘻嘻]","id":43}

Regular‑expression matching code in HarmonyOS:

let reg = RegExp(EmoticonManager.getInstance().emojiRegExpStr, 'g') // regex string
let result = content.matchAll(reg) // iterable matches
let next = result.next()
while (next.done == false) {
  let matchArr = next.value
  // split string here
  next = result.next()
}

The split result is transformed into a data model array, for example:

[
  { content: "第一次见面...", type: Text, resource: NULL },
  { content: "[色]", type: Emoji, resource: xxxx },
  { content: "这该死的羁绊~", type: Text, resource: NULL }
]

These models are then iterated to build the final rich text:

Text(){
  ForEach(this.model.getDecodedContentArr(), (element) => {
    if (element.type == CommentTextType.Text) {
      Span(element.content).onClick(() => { this.openCommentInput() })
    }
    if (element.type == CommentTextType.Emoji && element.resource != null) {
      ImageSpan(element.resource)
        .width(EmoticonManager.emojiSideLengthForFontSize(this.contentFontSize))
        .height(EmoticonManager.emojiSideLengthForFontSize(this.contentFontSize))
        .verticalAlign(ImageSpanAlignment.CENTER)
        .onClick(() => { this.openCommentInput() })
    }
  })
}

Emoji configuration can be stored locally or fetched from a remote server. Local configuration is a static JSON string inside a class, parsed with plainToClass . Remote configuration is downloaded via request.downloadFile , decompressed with zlib.decompressFile , and accessed through a generated file URI.

The article also covers the use of RichEditor as a rich‑text input box, controlled by a RichEditorController . A custom keyboard component can be injected via the customKeyboard property, allowing emoji insertion and deletion.

RichEditor({controller: this.editorController})
  .key(this.editorKey)
  .customKeyboard(this.useCustomKeyboard ? this.emojiKeyboard() : undefined)

@Builder
emojiKeyboard() {
  EmojiKeyboard({
    currentWidth: this.currentWidth,
    emojiOnClick: (model) => { this.emojiOnClick(model) },
    deleteOnClick: () => { this.emojiOnDelete() }
  })
    .backgroundColor('#F2F5F7')
    .width('100%')
    .height(this.emojiKeyboardHeight)
    .onAreaChange((oldValue, newValue) => {
      if (typeof newValue.width === 'number') {
        this.currentWidth = newValue.width as number
      }
    })
}

emojiOnClick(model) {
  this.editorController.addImageSpan(
    EmoticonManager.getInstance().getPixelMap(model.description),
    { imageStyle: { size: [EmoticonManager.emojiSideLengthForFontSize(this.fontSize),
                     EmoticonManager.emojiSideLengthForFontSize(this.fontSize)],
                     verticalAlign: ImageSpanAlignment.CENTER },
      offset: this.editorController.getCaretOffset() })
}

emojiOnDelete() {
  const currentIndex = this.editorController.getCaretOffset()
  if (currentIndex > 0) {
    this.editorController.deleteSpans({ start: currentIndex - 1, end: currentIndex })
  }
}

To retrieve the entered rich text for submission, the controller’s getSpans API returns an array of mixed span objects. Since HarmonyOS lacks a direct type‑checking method, the presence of the imageStyle property is used to differentiate RichEditorImageSpanResult from RichEditorTextSpanResult . Text spans provide the original string via .value , while image spans provide a resource URI that can be mapped back to the corresponding emoji keyword using the configuration table.

frontend developmentHarmonyOSRich Textcustom-keyboardEmoji IntegrationText Component
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.