• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Rich Text (RichEditor)
2**RichEditor** is a component that supports interactive text editing and mixture of text and imagery. It is typically used to handle user inputs with mixed content, such as comment sections that allow for image input. For details, see RichEditor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md).
3
4## Creating a RichEditor Component
5You create a **RichEditor** component by calling an API, which varies depending on the type of component you want to create.
6
7### Creating a RichEditor Component Without Using a Styled String
8```ts
9RichEditor(value: RichEditorOptions)
10```
11Creates a **RichEditor** component with the initialization options specified by **RichEditorOptions**.
12
13```ts
14controller: RichEditorController = new RichEditorController();
15options: RichEditorOptions = { controller: this.controller };
16
17RichEditor(this.options)
18    .onReady(() => {
19        this.controller.addTextSpan('Create a RichEditor component without using a styled string.', {
20            style: {
21                fontColor: Color.Black,
22                fontSize: 15
23            }
24        })
25    })
26```
27![alt text](figures/richeditor_image_options.gif)
28
29### Creating a RichEditor Component Using a Styled String
30```ts
31RichEditor(options: RichEditorStyledStringOptions)
32```
33
34Creates a **RichEditor** component with the initialization options specified by **RichEditorStyledStringOptions**.
35
36```ts
37mutableStyledString: MutableStyledString = new MutableStyledString("Create a RichEditor component using a styled string.",
38    [{
39        start: 0,
40        length: 5,
41        styledKey: StyledStringKey.FONT,
42        styledValue: this.fontStyle
43    }]);
44
45controller: RichEditorStyledStringController = new RichEditorStyledStringController();
46options: RichEditorStyledStringOptions = {controller: this.controller};
47
48RichEditor(this.options)
49    .onReady(() => {
50        this.controller.setStyledString(this.mutableStyledString);
51    })
52```
53![alt text](figures/richeditor_image_stylestringoptions.gif)
54
55## Setting Attributes
56
57### Setting the Custom Context Menu on Text Selection
58
59You can set custom context menu on text selection using the [bindSelectionMenu](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#bindselectionmenu) API, which includes the following parameters:
60
61**spanType**: type of the menu, with the default being text.<br>**content**: content of the menu.<br>**responseType**: response type of the menu, with the default being a long press.<br>**options**: options of the menu, allowing you to set callbacks for when the menu appears or disappears.
62
63If the custom menu is too long, embed a **Scroll** component to prevent the keyboard from being blocked.
64
65```ts
66RichEditor(this.options)
67    .onReady(() => {
68        this.controller.addTextSpan('The component has a custom menu that can be triggered by a long press.', {
69            style: {
70                fontColor: Color.Black,
71                fontSize: 18
72            }
73        })
74    })
75    .bindSelectionMenu(RichEditorSpanType.TEXT, this.SystemMenu, ResponseType.LongPress, {
76        onDisappear: () => {
77            this.sliderShow = false
78        }
79    })
80    .width(300)
81    .height(300)
82
83@Builder
84SystemMenu() {
85    Column() {
86            Menu() {
87                    if (this.controller) {
88                        MenuItemGroup() {
89                            MenuItem({
90                                startIcon: this.theme.cutIcon,
91                                content: "Cut",
92                                labelInfo: "Ctrl+X",
93                            })
94                            MenuItem({
95                                startIcon: this.theme.copyIcon,
96                                content: "Copy",
97                                labelInfo: "Ctrl+C"
98                            })
99                            MenuItem({
100                                startIcon: this.theme.pasteIcon,
101                                content: "Paste",
102                                labelInfo: "Ctrl+V"
103                            })
104                        }
105                    }
106                }
107                .radius(this.theme.containerBorderRadius)
108                .clip(true)
109                .backgroundColor(Color.White)
110                .width(this.theme.defaultMenuWidth)
111        }
112        .width(this.theme.defaultMenuWidth)
113}
114```
115
116![alt text](figures/richeditor_image_bindselectionmenu.gif)
117
118### Setting the Color of the Caret and Selection Handle in the Text Box
119
120You can set the color of the caret and selection handle in the text box using the [caretColor](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#caretcolor12) API.
121
122```ts
123RichEditor(this.options)
124    .onReady(() => {
125        this.controller.addTextSpan('The component has the color set for the caret and selection handle.', {
126            style: {
127                fontColor: Color.Black,
128                fontSize: 15
129            }
130        })
131    })
132    .caretColor(Color.Orange)
133    .width(300)
134    .height(300)
135```
136
137![alt text](figures/richeditor_image_caretcolor.gif)
138
139### Setting Placeholder Text
140
141You 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.
142
143In the API, **value** indicates the placeholder text displayed when there is no input; **style** indicates the font style for the placeholder text. If not specified, the style follows the theme settings.
144
145```ts
146RichEditor(this.options)
147    .placeholder("Enter your content here", {
148        fontColor: Color.Gray,
149        font: {
150            size: 15,
151            weight: FontWeight.Normal,
152            family: "HarmonyOS Sans",
153            style: FontStyle.Normal
154        }
155    })
156    .width(300)
157    .height(300)
158```
159
160![alt text](figures/richeditor_image_placeholder.gif)
161
162For details about all available attributes, see [RichEditor Attributes](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#attributes).
163
164## Adding Events
165### Adding a Callback for Component Initialization
166
167Use 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.
168
169In the API, **callback** indicates the callback invoked when the **RichEditor** component has completed initialization.
170
171```ts
172RichEditor(this.options)
173    .onReady(() => {
174        this.controller.addTextSpan('The onReady callback content is preset text within the component.', {
175            style: {
176                fontColor: Color.Black,
177                fontSize: 15
178            }
179        })
180    })
181```
182
183![alt text](figures/richeditor_image_onReady.gif)
184
185### Adding a Callback for Content Selection
186
187Use 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.
188
189In **callback**, [RichEditorSelection](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorselection) provides information about all the selected content.
190
191The callback can be invoked in either of the following ways: (1) If content is selected with the mouse left button, the callback is invoked after the left button is released. (2) If content is selected with a finger, the callback is invoked after the finger is lifted.
192
193```ts
194RichEditor(this.options)
195    .onReady(() => {
196        this.controller.addTextSpan('Select this text to invoke the onSelect callback.', {
197            style: {
198                fontColor: Color.Black,
199                fontSize: 15
200            }
201        })
202    })
203    .onSelect((value: RichEditorSelection) => {
204        this.controller1.addTextSpan(JSON.stringify(value), {
205            style: {
206                fontColor: Color.Gray,
207                fontSize: 10
208            }
209        })
210    })
211    .width(300)
212    .height(50)
213Text('View callback content:').fontSize(10).fontColor(Color.Gray).width(300)
214RichEditor(this.options1)
215    .width(300)
216    .height(70)
217 ```
218
219![alt text](figures/richeditor_image_onSelect.gif)
220
221### Adding Callbacks for Before and After Text and Image Changes
222
223Use the [onWillChange](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#onwillchange12) API to add a callback invoked before text or image changes. Use the [onDidChange](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#ondidchange12) API to add a callback invoked after text or image changes.
224
225In the **onWillChange** callback, [RichEditorChangeValue](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorchangevalue12) provides information about the text and image change; a boolean value indicates whether the change is allowed (**true**) or not allowed (**false**).
226
227In the **onDidChange** callback, [OnDidChangeCallback](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#ondidchangecallback12) provides the content range before and after the text or image change.
228
229The **RichEditor** component constructed with [RichEditorStyledStringOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorstyledstringoptions12) does not support these two types of callbacks.
230
231```ts
232RichEditor(this.options)
233    .onReady(() => {
234        this.controller.addTextSpan('The callback is invoked before the text or image change.\nThe callback is invoked after the text or image change.', {
235            style: {
236                fontColor: Color.Black,
237                fontSize: 15
238            }
239        })
240    })
241    .onWillChange((value: RichEditorChangeValue) => {
242        this.controller1.addTextSpan('The callback is invoked before the text or image change: \n' + JSON.stringify(value), {
243            style: {
244                fontColor: Color.Gray,
245                fontSize: 10
246            }
247        })
248        return true;
249    })
250    .onDidChange((rangeBefore: TextRange, rangeAfter: TextRange) => {
251        this.controller1.addTextSpan('\nThe callback is invoked after the text or image change: \nrangeBefore: ' + JSON.stringify(rangeBefore) + '\nrangeAfter: ' + JSON.stringify(rangeBefore), {
252            style: {
253                fontColor: Color.Gray,
254                fontSize: 10
255            }
256        })
257        return true;
258    })
259    .width(300)
260    .height(50)
261Text('View callback content:').fontSize(10).fontColor(Color.Gray).width(300)
262RichEditor(this.options1)
263    .width(300)
264    .height(70)
265```
266
267![alt text](figures/richeditor_image_ondid.gif)
268
269### Adding Callbacks for Before and After Content Input in the Input Method
270
271Use the [aboutToIMEInput](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#abouttoimeinput) API to add a callback invoked when content is about to be entered in the input method. Use the [onIMEInputComplete](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#onimeinputcomplete) method to add a callback invoked when text input in the input method is complete.
272
273In the **aboutToIMEInput** callback, [RichEditorInsertValue](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorinsertvalue) provides information about the content to be entered in the input method; a boolean value indicates whether the content is inserted (**true**) or not (**false**).
274
275In the **onIMEInputComplete** callback, [RichEditorTextSpanResult](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditortextspanresult) provides information about the text span after the text input is completed.
276
277The **RichEditor** component constructed with [RichEditorStyledStringOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorstyledstringoptions12) does not support these two types of callbacks.
278
279```ts
280RichEditor(this.options)
281          .onReady(() => {
282            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.' , {
283              style: {
284                fontColor: Color.Black,
285                fontSize: 15
286              }
287            })
288          })
289          .aboutToIMEInput((value: RichEditorInsertValue) => {
290            this.controller1.addTextSpan('The callback is invoked before content input in the input method: \n'+JSON.stringify(value), {
291              style: {
292                fontColor: Color.Gray,
293                fontSize: 10
294              }
295            })
296            return true;
297          })
298          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
299            this.controller1.addTextSpan('The callback is invoked when text input in the input method is complete: \n'+ JSON.stringify(value), {
300              style: {
301                fontColor: Color.Gray,
302                fontSize: 10
303              }
304            })
305            return true;
306          })
307          .width(300)
308          .height(50)
309Text('View callback content:').fontSize(10).fontColor(Color.Gray).width(300)
310RichEditor(this.options1)
311    .width(300)
312    .height(70)
313```
314
315![alt text](figures/richeditor_image_aboutToIMEInput2.0.gif)
316
317### Adding a Callback for Before Paste Completion
318
319Use 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.
320
321In the API, **callback** is used to define the user paste event.
322
323By default, only plain text can be pasted. You can use this API to override the default system behavior so that both images and text can be pasted.
324
325```ts
326RichEditor(this.options)
327    .onReady(() => {
328        this.controller.addTextSpan('Copy and paste operations on this text trigger the corresponding callbacks.', {
329            style: {
330                fontColor: Color.Black,
331                fontSize: 15
332            }
333        })
334    })
335    .onPaste(() => {
336        this.controller1.addTextSpan ('The onPaste callback is invoked.\n', {
337            style: {
338                fontColor: Color.Gray,
339                fontSize: 10
340            }
341        })
342    })
343    .width(300)
344    .height(70)
345```
346
347### Adding a Callback for Before Cut Completion
348
349Use 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.
350
351In the API, **callback** is used to define the user cut event.
352
353By default, only plain text can be cut. You can use this API to override the default system behavior so that both images and text can be cut.
354
355```ts
356RichEditor(this.options)
357    .onReady(() => {
358        this.controller.addTextSpan('Copy and paste operations on this text trigger the corresponding callbacks.', {
359            style: {
360                fontColor: Color.Black,
361                fontSize: 15
362            }
363        })
364    })
365    .onCut(() => {
366        this.controller1.addTextSpan ('The onCut callback is invoked.\n', {
367            style: {
368                fontColor: Color.Gray,
369                fontSize: 10
370            }
371        })
372    })
373    .width(300)
374    .height(70)
375```
376
377### Adding a Callback for Before Copy Completion
378
379Use 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.
380
381In the API, **callback** is used to define the user copy event.
382
383By default, only plain text can be copied. You can use this API to override the default system behavior so that both images and text can be copied.
384
385```ts
386RichEditor(this.options)
387    .onReady(() => {
388        this.controller.addTextSpan('Copy and paste operations on this text trigger the corresponding callbacks.', {
389            style: {
390                fontColor: Color.Black,
391                fontSize: 15
392            }
393        })
394    })
395    .onCopy(() => {
396        this.controller1.addTextSpan ('The onCopy callback is invoked.\n', {
397            style: {
398                fontColor: Color.Gray,
399                fontSize: 10
400            }
401        })
402    })
403    .width(300)
404    .height(70)
405```
406
407![alt text](figures/richeditor_image_oncut_paste_copy.gif)
408
409
410For details about all available events, see [RichEditor Events](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#events).
411
412## Setting the Typing Style
413
414Use the [setTypingStyle](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#settypingstyle12) API to set the typing style.
415
416In the API, **value** indicates the preset typing style.
417
418```ts
419RichEditor(this.options)
420    .onReady(() => {
421        this.controller.addTextSpan('Click the button to change the preset typing style.', {
422            style: {
423                fontColor: Color.Black,
424                fontSize: 15
425            }
426        })
427    })
428    .width(300)
429    .height(60)
430Button('setTypingStyle', {
431        buttonStyle: ButtonStyleMode.NORMAL
432    })
433    .height(30)
434    .fontSize(13)
435    .onClick(() => {
436        this.controller.setTypingStyle({
437            fontWeight: 'medium',
438            fontColor: Color.Pink,
439            fontSize: 15,
440            fontStyle: FontStyle.Italic,
441            decoration: {
442                type: TextDecorationType.Underline,
443                color: Color.Gray
444            }
445        })
446    })
447```
448
449![alt text](figures/richeditor_image_setTypingStyle.gif)
450
451## Setting Highlight for Selected Content
452
453Use the [setSelection](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#setselection12) API to configure the component to highlight the background of the selected portion.
454
455In the API:<br>**selectionStart**: start position of the selection.<br>selectionEnd: end position of the selection. If both **selectionStart** and **selectionEnd** are set to **-1**, the entire content is selected.
456
457If this API is called when the text box is not focused, the selected effect is not displayed.
458
459```ts
460RichEditor(this.options)
461    .onReady(() => {
462        this.controller.addTextSpan('Click the button to select the text at positions 0 to 2 here.', {
463            style: {
464                fontColor: Color.Black,
465                fontSize: 15
466            }
467        })
468    })
469    .width(300)
470    .height(60)
471Button('setSelection(0,2)', {
472        buttonStyle: ButtonStyleMode.NORMAL
473    })
474    .height(30)
475    .fontSize(13)
476    .onClick(() => {
477        this.controller.setSelection(0, 2)
478    })
479```
480
481![alt text](figures/richeditor_image_set_selection.gif)
482
483## Adding a Text Span
484
485In addition to directly entering content into the component, you can also add a text span using the [addTextSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addtextspan) API.
486
487In the API, **value** indicates the text content to add, and **options** indicates the text options, which include the offset position where the text is added and the text style information ([RichEditorParagraphStyle](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditortextspanoptions)).
488
489If the cursor in the component is blinking, the cursor position is updated to be after the inserted text span.
490
491```ts
492RichEditor(this.options)
493    .onReady(() => {
494        this.controller.addTextSpan('Click the button to add text here.', {
495            style: {
496                fontColor: Color.Black,
497                fontSize: 15
498            }
499        })
500    })
501    .width(300)
502    .height(100)
503Button('addTextSpan', {
504        buttonStyle: ButtonStyleMode.NORMAL
505    })
506    .height(30)
507    .fontSize(13)
508    .onClick(() => {
509        this.controller.addTextSpan('Add text.')
510    })
511```
512
513![alt text](figures/richeditor_image_add_text.gif)
514
515## Adding an Image Span
516
517Use the [addImageSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addimagespan) API to add an image span.
518
519In the API, **value** indicates the image content to be added, and **options** indicates the image options, which include the offset position where the image is added and the image style information ([RichEditorImageSpanOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorimagespanoptions)).
520
521Adds an image span. If the cursor in the component is blinking, the cursor position is updated to be after the inserted image span.
522
523```ts
524RichEditor(this.options)
525    .onReady(() => {
526        this.controller.addTextSpan('Click the button to add an image here.', {
527            style: {
528                fontColor: Color.Black,
529                fontSize: 15
530            }
531        })
532    })
533    .width(300)
534    .height(100)
535Button('addImageSpan', {
536        buttonStyle: ButtonStyleMode.NORMAL
537    })
538    .height(30)
539    .fontSize(13)
540    .onClick(() => {
541        this.controller.addImageSpan($r("app.media.startIcon"), {
542            imageStyle: {
543                size: ["57px", "57px"]
544            }
545        })
546    })
547```
548
549![alt text](figures/richeditor_image_add_image.gif)
550
551## Adding a Builder Span
552Use the [addBuilderSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addbuilderspan11) API to add a builder span.
553
554In the API, **value** indicates the content created by the builder, and **options** indicates the builder options, which allow you to set the index of this builder in the **RichEditor** component through [RichEditorBuilderSpanOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorbuilderspanoptions11). Each text character is considered a single unit.
555
556```ts
557@Builder
558TextBuilder() {
559    Row() {
560            Image($r('app.media.startIcon')).width(50).height(50).margin(16)
561            Column() {
562                Text("Text.txt").fontWeight (FontWeight.Bold).fontSize(16)
563                Text("123.45KB").fontColor('#8a8a8a').fontSize(12)
564            }.alignItems(HorizontalAlign.Start)
565        }.backgroundColor('#f4f4f4')
566        .borderRadius("20")
567        .width(220)
568}
569
570Button('addBuilderSpan', {
571        buttonStyle: ButtonStyleMode.NORMAL
572    })
573    .height(30)
574    .fontSize(13)
575    .onClick(() => {
576        this.my_builder = () => {
577            this.TextBuilder()
578        }
579        this.controller.addBuilderSpan(this.my_builder)
580    })
581```
582![alt text](figures/richeditor_image_add_builder_span2.0.gif)
583
584## Adding a Symbol Span
585
586Use the [addSymbolSpan](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#addsymbolspan11) AOU to add a symbol span.
587
588In the API, **value** indicates the content of the symbol span, and **options** indicates options of the symbol span, which are used to set the offset position and style information of the symbol span ([RichEditorSymbolSpanOptions](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorsymbolspanoptions11)).
589
590If the cursor in the component is blinking, the cursor position is updated to be after the inserted symbol span.
591
592Currently, gestures, copying, and dragging are not supported for the symbol span.
593
594```ts
595RichEditor(this.options)
596    .onReady(() => {
597        this.controller.addTextSpan('Click the button to add a symbol here.', {
598            style: {
599                fontColor: Color.Black,
600                fontSize: 15
601            }
602        })
603    })
604    .width(300)
605    .height(100)
606Button('addSymbolSpan', {
607        buttonStyle: ButtonStyleMode.NORMAL
608    })
609    .height(30)
610    .fontSize(13)
611    .onClick(() => {
612        this.controller.addSymbolSpan($r("sys.symbol.basketball_fill"), {
613            style: {
614                fontSize: 30
615            }
616        })
617    })
618```
619![alt text](figures/richeditor_image_add_SymbolSpan.gif)
620
621## Obtaining Span Information
622
623Use the [getSpans](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#getspans) API to obtain the span information of the component.
624
625In the API, **value** indicates the range of the target span. The return value is an array of either [RichEditorTextSpanResult](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditortextspanresult) or [RichEditorImageSpanResult](../reference/apis-arkui/arkui-ts/ts-basic-components-richeditor.md#richeditorimagespanresult), which includes information about text and image spans.
626
627```ts
628RichEditor(this.options)
629    .onReady(() => {
630        this.controller.addTextSpan('Click the button to obtain the span information.', {
631            style: {
632                fontColor: Color.Black,
633                fontSize: 15
634            }
635        })
636    })
637    .width(300)
638    .height(50)
639Text('View the return value of getSpans: ').fontSize (10).fontColor(Color.Gray).width(300)
640RichEditor(this.options1)
641    .width(300)
642    .height(50)
643Button('getSpans', {
644        buttonStyle: ButtonStyleMode.NORMAL
645    })
646    .height(30)
647    .fontSize(13)
648    .onClick(() => {
649        this.controller1.addTextSpan(JSON.stringify(this.controller.getSpans()), {
650            style: {
651                fontColor: Color.Gray,
652                fontSize: 10
653            }
654        })
655
656    })
657```
658![alt text](figures/richeditor_image_getspan.gif)
659