1# Rich Text (RichEditor)
2**RichEditor** is a component that supports interactive text editing and mixture of text and images. It is typically used in scenarios where mixed-content user input is expected, such as comment sections that accept both image and text submissions. For details, see [RichEditor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md).
3
4## Creating a RichEditor Component
5You can create a **RichEditor** component with or without a styled string.
6
7### Creating a RichEditor Component Without a Styled String
8Use the **RichEditor(value: [RichEditorOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditoroptions))** API to generate a **RichEditor** component from scratch. This approach is typically employed when you wish to present straightforward text and image content, for example, contact details. It can also serve in instances where a consistent content format is desired, such as in certain code editors.
9
10```ts
11controller: RichEditorController = new RichEditorController();
12options: RichEditorOptions = { controller: this.controller };
13
14RichEditor(this.options)
15    .onReady(() => {
16        this.controller.addTextSpan('Create a RichEditor component without using a styled string.', {
17            style: {
18                fontColor: Color.Black,
19                fontSize: 15
20            }
21        })
22    })
23```
24![alt text](figures/richeditor_image_options.gif)
25
26### Creating a RichEditor Component with a Styled String
27Alternatively, you can use the **RichEditor(options: [RichEditorStyledStringOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorstyledstringoptions12))** API to create a **RichEditor** component that is based on a styled string. This approach is particularly useful when you aim to enhance the GUI's aesthetics and emphasize the content,
28
29because it allows for a variety of text formatting options, including changing font size, adding font colors, making text interactive, and custom text rendering. In addition, this approach offers an array of style objects that cover a range of common text formatting styles, such as text with decorative lines, line height, and shadow effects.
30
31```ts
32mutableStyledString: MutableStyledString = new MutableStyledString("Create a RichEditor component using a styled string.",
33    [{
34        start: 0,
35        length: 5,
36        styledKey: StyledStringKey.FONT,
37        styledValue: this.fontStyle
38    }]);
39
40controller: RichEditorStyledStringController = new RichEditorStyledStringController();
41options: RichEditorStyledStringOptions = {controller: this.controller};
42
43RichEditor(this.options)
44    .onReady(() => {
45        this.controller.setStyledString(this.mutableStyledString);
46    })
47```
48![alt text](figures/richeditor_image_stylestringoptions.gif)
49
50## Setting Attributes
51
52### Setting the Custom Context Menu on Text Selection
53You can set a custom context menu on text selection using the [bindSelectionMenu](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#bindselectionmenu) API.
54
55By default, the context menu on text selection includes the copy, cut, and select all options. You can offer additional options for enhanced interactions, for example, a translate option for multilingual support or a bold option for emphasizing selected text.
56
57If the custom menu is too long, consider embedding a **Scroll** component to prevent the keyboard from being blocked.
58
59```ts
60RichEditor(this.options)
61    .onReady(() => {
62        this.controller.addTextSpan('The component has a custom menu that can be triggered by a long press.', {
63            style: {
64                fontColor: Color.Black,
65                fontSize: 18
66            }
67        })
68    })
69    .bindSelectionMenu(RichEditorSpanType.TEXT, this.SystemMenu, ResponseType.LongPress, {
70        onDisappear: () => {
71            this.sliderShow = false
72        }
73    })
74    .width(300)
75    .height(300)
76
77@Builder
78SystemMenu() {
79    Column() {
80            Menu() {
81                    if (this.controller) {
82                        MenuItemGroup() {
83                            MenuItem({
84                                startIcon: this.theme.cutIcon,
85                                content: "Cut",
86                                labelInfo: "Ctrl+X",
87                            })
88                            MenuItem({
89                                startIcon: this.theme.copyIcon,
90                                content: "Copy",
91                                labelInfo: "Ctrl+C"
92                            })
93                            MenuItem({
94                                startIcon: this.theme.pasteIcon,
95                                content: "Paste",
96                                labelInfo: "Ctrl+V"
97                            })
98                        }
99                    }
100                }
101                .radius(this.theme.containerBorderRadius)
102                .clip(true)
103                .backgroundColor(Color.White)
104                .width(this.theme.defaultMenuWidth)
105        }
106        .width(this.theme.defaultMenuWidth)
107}
108```
109
110![alt text](figures/richeditor_image_bindselectionmenu.gif)
111
112### Setting Caret and Selection Handle Colors in the Text Box
113You can set the caret and selection handle colors in the text box using the [caretColor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#caretcolor12) API.
114
115This feature allows for a more distinct visual representation of the caret and text selection, which can significantly aid users in navigating through complex UI that incorporate various input fields. It can also be particularly beneficial for text boxes that signify special features or states, such as a password text area.
116
117```ts
118RichEditor(this.options)
119    .onReady(() => {
120        this.controller.addTextSpan('The component has the color set for the caret and selection handle.', {
121            style: {
122                fontColor: Color.Black,
123                fontSize: 15
124            }
125        })
126    })
127    .caretColor(Color.Orange)
128    .width(300)
129    .height(300)
130```
131
132![alt text](figures/richeditor_image_caretcolor.gif)
133
134### Setting Placeholder Text
135You can set the placeholder text, which is displayed when there is no input, using the [placeholder](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#placeholder12) API.
136
137Placeholder text serves as a useful cue, assisting users in navigating through your application's UI, particularly in scenarios where text areas require specific attention or instructions, such as a login screen, or a text editing box with a character limit.
138
139```ts
140RichEditor(this.options)
141    .placeholder("Enter your content here", {
142        fontColor: Color.Gray,
143        font: {
144            size: 15,
145            weight: FontWeight.Normal,
146            family: "HarmonyOS Sans",
147            style: FontStyle.Normal
148        }
149    })
150    .width(300)
151    .height(300)
152```
153
154![alt text](figures/richeditor_image_placeholder.gif)
155
156For details about all available attributes, see [RichEditor Attributes](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#attributes).
157
158## Adding Events
159
160### Adding a Callback for Component Initialization
161Use the [onReady](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#onready) API to add a callback that is invoked after the component has been initialized.
162
163This callback can be used to effectively display rich content including images, texts, and emoticons after the component is initialized. When the **RichEditor** component is used to display news, this callback can initiate the process of obtaining image and text data from the server. The obtained data is then populated into the component, ensuring that the complete news content is promptly displayed on the page after initialization.
164
165```ts
166RichEditor(this.options)
167    .onReady(() => {
168        this.controller.addTextSpan('The onReady callback content is preset text within the component.', {
169            style: {
170                fontColor: Color.Black,
171                fontSize: 15
172            }
173        })
174    })
175```
176
177![alt text](figures/richeditor_image_onReady.gif)
178
179### Adding a Callback for Content Selection
180Use the [onSelect](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#onselect) API to add a callback that is invoked when content within the component is selected.
181
182This callback can be used to enhance the user experience following text selection For example, it can be used to trigger a context menu, allowing users to modify text styles, or to perform content analysis and processing on the selected text, providing input suggestions and thereby improving the efficiency and convenience of text editing.
183
184The callback can be triggered in two ways: by pressing and releasing the left mouse button to select content, or by selecting content with a finger touch and releasing the finger.
185
186```ts
187RichEditor(this.options)
188    .onReady(() => {
189        this.controller.addTextSpan('Select this text to invoke the onSelect callback.', {
190            style: {
191                fontColor: Color.Black,
192                fontSize: 15
193            }
194        })
195    })
196    .onSelect((value: RichEditorSelection) => {
197        this.controller1.addTextSpan(JSON.stringify(value), {
198            style: {
199                fontColor: Color.Gray,
200                fontSize: 10
201            }
202        })
203    })
204    .width(300)
205    .height(50)
206Text('View callback content:').fontSize(10).fontColor(Color.Gray).width(300)
207RichEditor(this.options1)
208    .width(300)
209    .height(70)
210```
211
212![alt text](figures/richeditor_image_onSelect.gif)
213
214### Adding Callbacks for Before and After Text and Image Changes
215Use the [onWillChange](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#onwillchange12) API to add a callback invoked before text or image changes. This callback is applicable to real-time data verification and notification. For example, it can be used to enable features such as detecting sensitive words and displaying an alert dialog box immediately, as well as real-time character count statistics and limitation.
216
217Use the [onDidChange](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#ondidchange12) API to add a callback invoked after text or image changes. This callback applies to content saving and synchronization. For example, it can be used to automatically save the latest content to the local host or synchronizing it to the server, and for updating content status and rendering.
218
219Note that the **RichEditor** component constructed with [RichEditorStyledStringOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorstyledstringoptions12) does not support these two types of callbacks.
220
221```ts
222RichEditor(this.options)
223    .onReady(() => {
224        this.controller.addTextSpan('The callback is invoked before the text or image change.\nThe callback is invoked after the text or image change.', {
225            style: {
226                fontColor: Color.Black,
227                fontSize: 15
228            }
229        })
230    })
231    .onWillChange((value: RichEditorChangeValue) => {
232        this.controller1.addTextSpan('The callback is invoked before the text or image change: \n' + JSON.stringify(value), {
233            style: {
234                fontColor: Color.Gray,
235                fontSize: 10
236            }
237        })
238        return true;
239    })
240    .onDidChange((rangeBefore: TextRange, rangeAfter: TextRange) => {
241        this.controller1.addTextSpan('\nThe callback is invoked after the text or image change: \nrangeBefore: ' + JSON.stringify(rangeBefore) + '\nrangeAfter: ' + JSON.stringify(rangeBefore), {
242            style: {
243                fontColor: Color.Gray,
244                fontSize: 10
245            }
246        })
247        return true;
248    })
249    .width(300)
250    .height(50)
251Text('View callback content:').fontSize(10).fontColor(Color.Gray).width(300)
252RichEditor(this.options1)
253    .width(300)
254    .height(70)
255```
256
257![alt text](figures/richeditor_image_ondid.gif)
258
259### Adding Callbacks for Before and After Content Input in the Input Method
260To facilitate intelligent input assistance, use [aboutToIMEInput](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#abouttoimeinput) to trigger a callback before adding input content, and [onIMEInputComplete](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#onimeinputcomplete) to trigger a callback after the input is complete.
261
262These callbacks can be used to provide text prediction before user input and to perform automatic error correction or format conversion after input completion.
263
264Note that the **RichEditor** component constructed with [RichEditorStyledStringOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorstyledstringoptions12) does not support these two types of callbacks.
265
266```ts
267RichEditor(this.options)
268          .onReady(() => {
269            this.controller.addTextSpan('The callback is invoked before content input in the input method.\nThe callback is invoked when text input in the input method is complete.' , {
270              style: {
271                fontColor: Color.Black,
272                fontSize: 15
273              }
274            })
275          })
276          .aboutToIMEInput((value: RichEditorInsertValue) => {
277            this.controller1.addTextSpan('The callback is invoked before content input in the input method: \n'+JSON.stringify(value), {
278              style: {
279                fontColor: Color.Gray,
280                fontSize: 10
281              }
282            })
283            return true;
284          })
285          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
286            this.controller1.addTextSpan('The callback is invoked when text input in the input method is complete: \n'+ JSON.stringify(value), {
287              style: {
288                fontColor: Color.Gray,
289                fontSize: 10
290              }
291            })
292            return true;
293          })
294          .width(300)
295          .height(50)
296Text('View callback content:').fontSize(10).fontColor(Color.Gray).width(300)
297RichEditor(this.options1)
298    .width(300)
299    .height(70)
300```
301
302![alt text](figures/richeditor_image_aboutToIMEInput2.0.gif)
303
304### Adding a Callback for Before Paste Completion
305Use the [onPaste](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#onpaste11) API to add a callback invoked when the paste is about to be completed.
306
307This is useful for content format processing, such as converting text containing HTML tags to a format supported by the **RichEditor** component and removing unnecessary tags or retaining only plain text content.
308
309You can use this API to override the default pasting behavior, which is limited to plain text, so that both images and text can be pasted.
310
311```ts
312RichEditor(this.options)
313    .onReady(() => {
314        this.controller.addTextSpan('Copy and paste operations on this text trigger the corresponding callbacks.', {
315            style: {
316                fontColor: Color.Black,
317                fontSize: 15
318            }
319        })
320    })
321    .onPaste(() => {
322        this.controller1.addTextSpan('The onPaste callback is invoked.\n', {
323            style: {
324                fontColor: Color.Gray,
325                fontSize: 10
326            }
327        })
328    })
329    .width(300)
330    .height(70)
331```
332
333### Adding a Callback for Before Cut Completion
334Use the [onCut](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#oncut12) API to add a callback invoked when text is about to be cut.
335
336This can be used to temporarily store the cut content, ensuring accurate restoration in subsequent pasting operations.
337
338You can use this API to override the default cutting behavior, which is limited to plain text, so that both images and text can be cut.
339
340```ts
341RichEditor(this.options)
342    .onReady(() => {
343        this.controller.addTextSpan('Copy and paste operations on this text trigger the corresponding callbacks.', {
344            style: {
345                fontColor: Color.Black,
346                fontSize: 15
347            }
348        })
349    })
350    .onCut(() => {
351        this.controller1.addTextSpan('The onCut callback is invoked.\n', {
352            style: {
353                fontColor: Color.Gray,
354                fontSize: 10
355            }
356        })
357    })
358    .width(300)
359    .height(70)
360```
361
362### Adding a Callback for Before Copy Completion
363Use the [onCopy](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#oncopy12) API to add a callback invoked when text is about to be copied.
364
365This callback applies to content backup and sharing. For example, the following operations can be performed in the callback: saving the copied content and its format information to a local backup folder, or automatically generating copywriting that includes the copied content and a product purchase link for users to paste and share.
366
367You can use this API to override the default copying behavior, which is limited to plain text, so that both images and text can be copied.
368
369```ts
370RichEditor(this.options)
371    .onReady(() => {
372        this.controller.addTextSpan('Copy and paste operations on this text trigger the corresponding callbacks.', {
373            style: {
374                fontColor: Color.Black,
375                fontSize: 15
376            }
377        })
378    })
379    .onCopy(() => {
380        this.controller1.addTextSpan('The onCopy callback is invoked.\n', {
381            style: {
382                fontColor: Color.Gray,
383                fontSize: 10
384            }
385        })
386    })
387    .width(300)
388    .height(70)
389```
390
391![alt text](figures/richeditor_image_oncut_paste_copy.gif)
392
393
394For details about all available events, see [RichEditor Events](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#events).
395
396## Setting the Typing Style
397Use the [setTypingStyle](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#settypingstyle11) API to set the typing style.
398
399This allows you to deliver a personalized writing experience. For example, you might want to use this API to automatically apply corresponding formats to different levels of headings (such as level-1 and level-2 headings) as users type.
400
401```ts
402RichEditor(this.options)
403    .onReady(() => {
404        this.controller.addTextSpan('Click the button to change the preset typing style.', {
405            style: {
406                fontColor: Color.Black,
407                fontSize: 15
408            }
409        })
410    })
411    .width(300)
412    .height(60)
413Button('setTypingStyle', {
414        buttonStyle: ButtonStyleMode.NORMAL
415    })
416    .height(30)
417    .fontSize(13)
418    .onClick(() => {
419        this.controller.setTypingStyle({
420            fontWeight: 'medium',
421            fontColor: Color.Pink,
422            fontSize: 15,
423            fontStyle: FontStyle.Italic,
424            decoration: {
425                type: TextDecorationType.Underline,
426                color: Color.Gray
427            }
428        })
429    })
430```
431
432![alt text](figures/richeditor_image_setTypingStyle.gif)
433
434## Setting Highlight for Selected Content
435Use the [setSelection](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#setselection11) API to configure the component to highlight the background of the selected portion.
436
437This API enables the implementation of text focus effects. For example, clicking a title or abstract can trigger the automatic selection and highlighting of the corresponding text content.
438
439If this API is called when the text box is not focused, the selection effect is not displayed.
440
441```ts
442RichEditor(this.options)
443    .onReady(() => {
444        this.controller.addTextSpan('Click the button to select the text at positions 0 to 2 here.', {
445            style: {
446                fontColor: Color.Black,
447                fontSize: 15
448            }
449        })
450    })
451    .width(300)
452    .height(60)
453Button('setSelection(0,2)', {
454        buttonStyle: ButtonStyleMode.NORMAL
455    })
456    .height(30)
457    .fontSize(13)
458    .onClick(() => {
459        this.controller.setSelection(0, 2)
460    })
461```
462
463![alt text](figures/richeditor_image_set_selection.gif)
464
465## Adding a Text Span
466In addition to directly entering content into the component, you can add a text span using the [addTextSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addtextspan) API.
467
468This API offers a way to diversify text styles. For example, you can use it to create mixed text styles.
469
470When the component is focused and the cursor is blinking, adding text content through **addTextSpan** updates the cursor position to the right of the newly added text.
471
472```ts
473RichEditor(this.options)
474    .onReady(() => {
475        this.controller.addTextSpan('Click the button to add text here.', {
476            style: {
477                fontColor: Color.Black,
478                fontSize: 15
479            }
480        })
481    })
482    .width(300)
483    .height(100)
484Button('addTextSpan', {
485        buttonStyle: ButtonStyleMode.NORMAL
486    })
487    .height(30)
488    .fontSize(13)
489    .onClick(() => {
490        this.controller.addTextSpan('Add text.')
491    })
492```
493
494![alt text](figures/richeditor_image_add_text.gif)
495
496## Adding an Image Span
497Use the [addImageSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addimagespan) API to add an image span.
498
499This API is useful in enriching and visualizing content. For example, you can use it to add images to news or data visualization graphics to documents.
500
501When the component is focused and the cursor is blinking, adding image content through **addImageSpan** updates the cursor position to the right of the newly added image.
502
503```ts
504RichEditor(this.options)
505    .onReady(() => {
506        this.controller.addTextSpan('Click the button to add an image here.', {
507            style: {
508                fontColor: Color.Black,
509                fontSize: 15
510            }
511        })
512    })
513    .width(300)
514    .height(100)
515Button('addImageSpan', {
516        buttonStyle: ButtonStyleMode.NORMAL
517    })
518    .height(30)
519    .fontSize(13)
520    .onClick(() => {
521        this.controller.addImageSpan($r("app.media.startIcon"), {
522            imageStyle: {
523                size: ["57px", "57px"]
524            }
525        })
526    })
527```
528
529![alt text](figures/richeditor_image_add_image.gif)
530
531## Adding @Builder Decorated Content
532Use [addBuilderSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addbuilderspan11) to add the content decorated by the @Builder decorator.
533
534This approach applies when you need to integrate customized complex components, such as custom charts.
535
536With this API, you can specify the addition position using [RichEditorBuilderSpanOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorbuilderspanoptions11). If no position is specified or an abnormal value is provided, the builder is appended to the end of all content.
537
538```ts
539@Builder
540TextBuilder() {
541    Row() {
542            Image($r('app.media.startIcon')).width(50).height(50).margin(16)
543            Column() {
544                Text("Text.txt").fontWeight(FontWeight.Bold).fontSize(16)
545                Text("123.45KB").fontColor('#8a8a8a').fontSize(12)
546            }.alignItems(HorizontalAlign.Start)
547        }.backgroundColor('#f4f4f4')
548        .borderRadius("20")
549        .width(220)
550}
551
552Button('addBuilderSpan', {
553        buttonStyle: ButtonStyleMode.NORMAL
554    })
555    .height(30)
556    .fontSize(13)
557    .onClick(() => {
558        this.my_builder = () => {
559            this.TextBuilder()
560        }
561        this.controller.addBuilderSpan(this.my_builder)
562    })
563```
564![alt text](figures/richeditor_image_add_builder_span2.0.gif)
565
566## Adding a Symbol Span
567Use the [addSymbolSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addsymbolspan11) API to add symbol content. This API enables the addition and display of special characters, such as mathematical symbols in academic papers.
568
569When the component is focused and the cursor is blinking, adding symbol content through **addSymbolSpan** updates the cursor position to the right of the newly added symbol.
570Currently, gestures, copying, and dragging are not supported for the symbol content.
571
572```ts
573RichEditor(this.options)
574    .onReady(() => {
575        this.controller.addTextSpan('Click the button to add a symbol here.', {
576            style: {
577                fontColor: Color.Black,
578                fontSize: 15
579            }
580        })
581    })
582    .width(300)
583    .height(100)
584Button('addSymbolSpan', {
585        buttonStyle: ButtonStyleMode.NORMAL
586    })
587    .height(30)
588    .fontSize(13)
589    .onClick(() => {
590        this.controller.addSymbolSpan($r("sys.symbol.basketball_fill"), {
591            style: {
592                fontSize: 30
593            }
594        })
595    })
596```
597![alt text](figures/richeditor_image_add_SymbolSpan.gif)
598
599## Obtaining the Image and Text Information in a Component
600Use the [getSpans](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#getspans) API to obtain information about all images and text in the component, including content, ID, style, and position. After obtaining the position information, you can update the style of the content in the specified range.
601
602This API is useful for obtaining and checking existing content styles, such as in template use cases, and for content parsing and processing, such as in text analysis applications.
603
604```ts
605RichEditor(this.options)
606    .onReady(() => {
607        this.controller.addTextSpan('Click the button to obtain the span information.', {
608            style: {
609                fontColor: Color.Black,
610                fontSize: 15
611            }
612        })
613    })
614    .width(300)
615    .height(50)
616Text('View the return value of getSpans: ').fontSize(10).fontColor(Color.Gray).width(300)
617RichEditor(this.options1)
618    .width(300)
619    .height(50)
620Button('getSpans', {
621        buttonStyle: ButtonStyleMode.NORMAL
622    })
623    .height(30)
624    .fontSize(13)
625    .onClick(() => {
626        this.controller1.addTextSpan(JSON.stringify(this.controller.getSpans()), {
627            style: {
628                fontColor: Color.Gray,
629                fontSize: 10
630            }
631        })
632
633    })
634```
635![alt text](figures/richeditor_image_getspan.gif)
636<!--RP1--><!--RP1End-->
637