1# RichEditor
2
3The **RichEditor** is a component that supports interactive text editing and mixture of text and imagery.
4
5>  **NOTE**
6>
7>  This component is supported since API version 10. Updates will be marked with a superscript to indicate their earliest API version.
8
9
10## Child Components
11
12Not supported
13
14
15## APIs
16
17RichEditor(value: RichEditorOptions)
18
19**Atomic service API**: This API can be used in atomic services since API version 11.
20
21**Parameters**
22
23| Name  | Type                                   | Mandatory  | Description       |
24| ----- | --------------------------------------- | ---- | ----------- |
25| value | [RichEditorOptions](#richeditoroptions) | Yes   | Options for initializing the component. |
26
27RichEditor(options: RichEditorStyledStringOptions)<sup>12+</sup>
28
29
30**Parameters**
31
32| Name  | Type                                   | Mandatory  | Description       |
33| ----- | --------------------------------------- | ---- | ----------- |
34| options | [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) | Yes   | Options for initializing the component. |
35
36## Attributes
37
38In addition to the [universal attributes](ts-universal-attributes-size.md), the following attributes are supported.
39
40>  **NOTE**
41>
42>  The **align** attribute supports only the start, center, and end options.
43
44### customKeyboard
45
46customKeyboard(value: CustomBuilder, options?: KeyboardOptions)
47
48Sets a custom keyboard.
49
50When a custom keyboard is set, activating the text box opens the specified custom component, instead of the system input method.
51
52The custom keyboard's height can be set through the **height** attribute of the custom component's root node, and its width is fixed at the default value.
53
54The custom keyboard is displayed on top of the current page, without compressing or raising the page.
55
56The custom keyboard cannot obtain focus, but it blocks gesture events.
57
58By default, the custom keyboard is closed when the input component loses the focus.
59
60When a custom keyboard is set, the text box does not support camera input, even when the device supports.
61
62**Atomic service API**: This API can be used in atomic services since API version 11.
63
64**System capability**: SystemCapability.ArkUI.ArkUI.Full
65
66**Parameters** 
67
68| Name               | Type                                       | Mandatory | Description                            |
69| --------------------- | ------------------------------------------- | ---- | -------------------------------- |
70| value                 | [CustomBuilder](ts-types.md#custombuilder8) | Yes  | Custom keyboard.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
71| options<sup>12+</sup> | [KeyboardOptions](#keyboardoptions12)       | No  | Whether to support keyboard avoidance. |
72
73### bindSelectionMenu
74
75bindSelectionMenu(spanType: RichEditorSpanType, content: CustomBuilder, responseType: ResponseType | RichEditorResponseType,
76    options?: SelectionMenuOptions)
77
78Sets the custom context menu on text selection. If the custom menu is too long, embed a [Scroll](./ts-container-scroll.md) component to prevent the keyboard from being blocked.
79
80**Atomic service API**: This API can be used in atomic services since API version 11.
81
82**System capability**: SystemCapability.ArkUI.ArkUI.Full
83
84**Parameters** 
85
86| Name      | Type                                                        | Mandatory | Description                                                     |
87| ------------ | ------------------------------------------------------------ | ---- | --------------------------------------------------------- |
88| spanType     | [RichEditorSpanType](#richeditorspantype)                    | Yes  | Menu type.<br> Default value:<br>RichEditorSpanType.TEXT    |
89| content      | [CustomBuilder](ts-types.md#custombuilder8)                  | Yes  | Menu content.                                             |
90| responseType |  [ResponseType](ts-appendix-enums.md#responsetype8) \| [RichEditorResponseType<sup>11+</sup>](ts-appendix-enums.md#richeditorresponsetype11) | Yes  | Response type of the menu.<br> Default value:<br>ResponseType.LongPress |
91| options      | [SelectionMenuOptions](#selectionmenuoptions11)              | No  | Menu options.                                             |
92
93### copyOptions
94
95copyOptions(value: CopyOptions)
96
97Specifies whether copy and paste is allowed for text content.
98
99If **copyOptions** is not set to **CopyOptions.None**, long-pressing the text content displays the context menu. If a custom context menu is defined through **bindSelectionMenu** or other approaches, it will be displayed.
100
101If **copyOptions** is set to **CopyOptions.None**, copy and paste is not allowed.
102
103**Atomic service API**: This API can be used in atomic services since API version 11.
104
105**System capability**: SystemCapability.ArkUI.ArkUI.Full
106
107**Parameters** 
108
109| Name | Type                                            | Mandatory | Description                                                        |
110| ------ | ------------------------------------------------ | ---- | ------------------------------------------------------------ |
111| value  | [CopyOptions](ts-appendix-enums.md#copyoptions9) | Yes  | Whether copy and paste is allowed for text content.<br>Default value: **CopyOptions.LocalDevice** |
112
113### enableDataDetector<sup>11+</sup>
114
115enableDataDetector(enable: boolean)
116
117Enables text recognition.
118
119The recognized entity is in the following style settings:<br>fontColor: Color.Blue<br>decoration: {<br>type: TextDecorationType.Underline,<br>color: Color.Blue<br>}
120
121For this API to work, the target device must provide the text recognition capability.
122
123When **enableDataDetector** is set to **true** and **dataDetectorConfig** is not set, all types of entities are recognized by default.
124
125When **copyOptions** is set to **CopyOptions.None**, the menu displayed after an entity is clicked does not provide text selection.
126
127This API does not work for the node text of **addBuilderSpan**.
128
129**Atomic service API**: This API can be used in atomic services since API version 12.
130
131**System capability**: SystemCapability.ArkUI.ArkUI.Full
132
133**Parameters** 
134
135| Name | Type   | Mandatory | Description                             |
136| ------ | ------- | ---- | --------------------------------- |
137| enable  | boolean | Yes  | Whether to enable text recognition.<br>Default value: **false** |
138
139### dataDetectorConfig<sup>11+</sup>
140
141dataDetectorConfig(config: TextDataDetectorConfig)
142
143Configures text recognition settings. This API must be used together with [enableDataDetector](#enabledatadetector11). It takes effect only when **enableDataDetector** is set to **true**.
144
145**Atomic service API**: This API can be used in atomic services since API version 12.
146
147**System capability**: SystemCapability.ArkUI.ArkUI.Full
148
149**Parameters** 
150
151| Name | Type                                               | Mandatory | Description                                                        |
152| ------ | --------------------------------------------------- | ---- | ------------------------------------------------------------ |
153| config | [TextDataDetectorConfig](#textdatadetectorconfig11) | Yes  | Text recognition configuration.<br>Default value: {<br>types: [ ],<br>onDetectResultUpdate: null<br>} |
154
155### enablePreviewText<sup>12+</sup>
156
157enablePreviewText(enable: boolean)
158
159Sets whether to enable preview text.
160
161**Atomic service API**: This API can be used in atomic services since API version 12.
162
163**System capability**: SystemCapability.ArkUI.ArkUI.Full
164
165**Parameters** 
166
167| Name | Type   | Mandatory | Description                             |
168| ------ | ------- | ---- | --------------------------------- |
169| enable  | boolean | Yes  | Whether to enable preview text.<br>Default value: **true** |
170
171### placeholder<sup>12+</sup>
172
173placeholder(value: ResourceStr, style?: PlaceholderStyle)
174
175Sets the placeholder text, which is displayed when there is no input.
176
177**Atomic service API**: This API can be used in atomic services since API version 12.
178
179**System capability**: SystemCapability.ArkUI.ArkUI.Full
180
181**Parameters** 
182
183| Name | Type                                   | Mandatory | Description                                                   |
184| ------ | --------------------------------------- | ---- | ------------------------------------------------------- |
185| value  | [ResourceStr](ts-types.md#resourcestr)  | Yes  | Placeholder text.                                   |
186| style  | [PlaceholderStyle](#placeholderstyle12) | No  | Style of the placeholder text.<br>By default, the style follows the theme. |
187
188### caretColor<sup>12+</sup>
189
190caretColor(value: ResourceColor)
191
192Sets the color of the caret and selection handle in the text box.
193
194**Atomic service API**: This API can be used in atomic services since API version 12.
195
196**System capability**: SystemCapability.ArkUI.ArkUI.Full
197
198**Parameters** 
199
200| Name | Type                                      | Mandatory | Description                                  |
201| ------ | ------------------------------------------ | ---- | -------------------------------------- |
202| value  | [ResourceColor](ts-types.md#resourcecolor) | Yes  | Color of the cursor and selection handle in the text box.<br>Default value: **'#007DFF'** |
203
204### selectedBackgroundColor<sup>12+</sup>
205
206selectedBackgroundColor(value: ResourceColor)
207
208Sets the background color of the selected text. If the opacity is not set, a 20% opacity will be used.
209
210**Atomic service API**: This API can be used in atomic services since API version 12.
211
212**System capability**: SystemCapability.ArkUI.ArkUI.Full
213
214**Parameters** 
215
216| Name | Type                                      | Mandatory | Description                                      |
217| ------ | ------------------------------------------ | ---- | ------------------------------------------ |
218| value  | [ResourceColor](ts-types.md#resourcecolor) | Yes  | Background color of the selected text.<br>By default, a 20% opacity is applied. |
219
220### editMenuOptions<sup>12+</sup>
221
222editMenuOptions(editMenu: EditMenuOptions)
223
224Sets the extended options of the custom context menu on selection, including the text content, icon, and callback.
225
226**Atomic service API**: This API can be used in atomic services since API version 12.
227
228**System capability**: SystemCapability.ArkUI.ArkUI.Full
229
230**Parameters** 
231
232| Name | Type                                         | Mandatory | Description                                         |
233| ------ | --------------------------------------------- | ---- | --------------------------------------------- |
234| editMenu  | [EditMenuOptions](ts-text-common.md#editmenuoptions) | No  | Extended options of the custom context menu on selection. |
235
236### enterKeyType<sup>12+</sup>
237
238enterKeyType(value: EnterKeyType)
239
240Sets the Enter key type of the soft keyboard.
241
242**Atomic service API**: This API can be used in atomic services since API version 12.
243
244**System capability**: SystemCapability.ArkUI.ArkUI.Full
245
246**Parameters** 
247
248| Name | Type  | Mandatory | Description                               |
249| ------ | ------ | ---- | ----------------------------------- |
250| value  | [EnterKeyType](ts-types.md#enterkeytype) | Yes  | Type of the Enter key.<br>Default value: **EnterKeyType.NEW_LINE** |
251
252### enableKeyboardOnFocus<sup>13+</sup>
253
254enableKeyboardOnFocus(isEnabled: boolean)
255
256Sets whether to enable the input method when the **RichEditor** component obtains focus in a way other than clicking.
257
258
259**Atomic service API**: This API can be used in atomic services since API version 13.
260
261**System capability**: SystemCapability.ArkUI.ArkUI.Full
262
263**Parameters** 
264
265| Name | Type | Mandatory | Description |
266| ------ | ------- | ---- | ----------------------------------------------------------- |
267| isEnabled  | boolean | Yes  | Whether to enable the input method when the component obtains focus in a way other than clicking.<br>Default value: **true** |
268
269## Events
270
271In addition to the [universal events](ts-universal-events-click.md), the following events are supported.
272
273### onReady
274
275onReady(callback:Callback\<void\>)
276
277Triggered when initialization of the component is completed.
278
279**Atomic service API**: This API can be used in atomic services since API version 11.
280
281**System capability**: SystemCapability.ArkUI.ArkUI.Full
282
283**Parameters** 
284
285| Name  | Type                                   | Mandatory  | Description       |
286| ----- | --------------------------------------- | ---- | ----------- |
287| callback |Callback\<void\> | Yes   | Invoked when initialization of the **RichEditor** component is complete. |
288
289### onSelect
290
291onSelect(callback:Callback\<[RichEditorSelection](#richeditorselection)\>)
292
293Invoked when content is selected.
294
295If a mouse device is used for selection, this callback is invoked when the mouse button is released. If a finger is used for selection, this callback is invoked when the finger is released.
296
297This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used.
298
299**Atomic service API**: This API can be used in atomic services since API version 11.
300
301**System capability**: SystemCapability.ArkUI.ArkUI.Full
302
303**Parameters** 
304
305| Name | Type                                       | Mandatory | Description                |
306| ------ | ------------------------------------------- | ---- | -------------------- |
307| callback | Callback\<[RichEditorSelection](#richeditorselection)\> | Yes  | Callback invoked when content is selected.<br>[RichEditorSelection](#richeditorselection) indicates information about all the selected spans. |
308
309### aboutToIMEInput
310
311aboutToIMEInput(callback:Callback\<[RichEditorInsertValue](#richeditorinsertvalue), boolean\>)
312
313Invoked when content is about to be entered in the input method.
314
315This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used.
316
317**Atomic service API**: This API can be used in atomic services since API version 11.
318
319**System capability**: SystemCapability.ArkUI.ArkUI.Full
320
321**Parameters** 
322
323| Name | Type                                       | Mandatory | Description                |
324| ------ | ------------------------------------------- | ---- | -------------------- |
325| callback | Callback\<[RichEditorInsertValue](#richeditorinsertvalue), boolean\> | Yes  | Callback invoked when content is about to be entered in the input method.<br/>[RichEditorInsertValue](#richeditorinsertvalue) indicates whether content will be entered in the input method.<br>**true**: Content is inserted.<br>**false**: Content is not inserted. |
326
327### onIMEInputComplete
328
329onIMEInputComplete(callback:Callback\<[RichEditorTextSpanResult](#richeditortextspanresult)\>)
330
331Invoked when text input in the input method is complete.
332
333This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used.
334
335**Atomic service API**: This API can be used in atomic services since API version 11.
336
337**System capability**: SystemCapability.ArkUI.ArkUI.Full
338
339**Parameters** 
340
341| Name | Type                                       | Mandatory | Description                |
342| ------ | ------------------------------------------- | ---- | -------------------- |
343| callback | Callback\<[RichEditorTextSpanResult](#richeditortextspanresult)\> | Yes | Callback invoked when text input in the input method is complete.<br/>[RichEditorTextSpanResult](#richeditortextspanresult) indicates the text span information after text input is complete. |
344
345### aboutToDelete
346
347aboutToDelete(callback:Callback\<[RichEditorDeleteValue](#richeditordeletevalue), boolean\>)
348
349Invoked when content is about to be deleted in the input method.
350
351This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used.
352
353**Atomic service API**: This API can be used in atomic services since API version 11.
354
355**System capability**: SystemCapability.ArkUI.ArkUI.Full
356
357**Parameters** 
358
359| Name | Type                                       | Mandatory | Description                |
360| ------ | ------------------------------------------- | ---- | -------------------- |
361| callback | Callback\<[RichEditorDeleteValue](#richeditordeletevalue), boolean\> | Yes | Callback invoked when content is about to be deleted in the input method.<br/>[RichEditorDeleteValue](#richeditordeletevalue) indicates the text or image span where the content to be deleted is located.<br>**true**: Content is deleted.<br>**false**: Content is not deleted. |
362
363### onDeleteComplete
364
365onDeleteComplete(callback:Callback\<void\>)
366
367Invoked when deletion in the input method is completed.
368
369This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used.
370
371**Atomic service API**: This API can be used in atomic services since API version 11.
372
373**System capability**: SystemCapability.ArkUI.ArkUI.Full
374
375**Parameters** 
376
377| Name  | Type                                   | Mandatory  | Description       |
378| ----- | --------------------------------------- | ---- | ----------- |
379| callback |Callback\<void\> | Yes   | Callback invoked when deletion in the input method is completed. |
380
381### onPaste<sup>11+</sup>
382
383onPaste(callback: [PasteEventCallback](#pasteeventcallback12) )
384
385Invoked when the paste is about to be completed. By default, only plain text can be pasted. You can use this API to overwrite the default system behavior so that both images and text can be pasted.
386
387**Atomic service API**: This API can be used in atomic services since API version 12.
388
389**System capability**: SystemCapability.ArkUI.ArkUI.Full
390
391**Parameters** 
392
393| Name | Type   | Mandatory | Description                         |
394| ------ | ------- | ---- | ----------------------------- |
395| callback | [PasteEventCallback](#pasteeventcallback12) | Yes  | Callback invoked when the paste is about to be completed. |
396
397### onSelectionChange<sup>12+</sup>
398
399onSelectionChange(callback:Callback\<[RichEditorRange](#richeditorrange)\>)
400
401Invoked when the content selection area changes or the caret position changes in the editing state. In the case of caret position changes, the start position of the content selection area is equal to the end position.
402
403**Atomic service API**: This API can be used in atomic services since API version 12.
404
405**System capability**: SystemCapability.ArkUI.ArkUI.Full
406
407**Parameters** 
408
409| Name  | Type                                   | Mandatory  | Description       |
410| ----- | --------------------------------------- | ---- | ----------- |
411| callback |Callback\<[RichEditorRange](#richeditorrange)\> | Yes   | Callback invoked when the content selection area changes or the caret position changes in the editing state.<br/>[RichEditorRange](#richeditorrange) indicates the start and end positions of the content selection area. |
412
413### onEditingChange<sup>12+</sup>
414
415onEditingChange(callback: Callback\<boolean\>)
416
417Invoked when the editing state of all content in the component changes.
418
419**Atomic service API**: This API can be used in atomic services since API version 12.
420
421**System capability**: SystemCapability.ArkUI.ArkUI.Full
422
423**Parameters** 
424
425| Name  | Type                                   | Mandatory  | Description       |
426| ----- | --------------------------------------- | ---- | ----------- |
427| callback | Callback\<boolean\> | Yes   | Callback invoked when the editing state of all content in the component changes. The value **true** indicates the editing state, and **false** indicates the non-editing state. |
428
429### onSubmit<sup>12+</sup>
430
431onSubmit(callback: SubmitCallback)
432
433Invoked when the Enter key on the soft keyboard is pressed.
434
435**Atomic service API**: This API can be used in atomic services since API version 12.
436
437**System capability**: SystemCapability.ArkUI.ArkUI.Full
438
439**Parameters** 
440
441| Name | Type   | Mandatory | Description                         |
442| ------ | ------- | ---- | ----------------------------- |
443| callback | [SubmitCallback](#submitcallback12) | Yes  | Callback used to return the result. |
444
445### onWillChange<sup>12+</sup>
446
447onWillChange(callback: Callback\<RichEditorChangeValue, boolean\>)
448
449Invoked when the text or image in the component is about to change.
450
451This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used.
452
453**Atomic service API**: This API can be used in atomic services since API version 12.
454
455**System capability**: SystemCapability.ArkUI.ArkUI.Full
456
457**Parameters** 
458
459| Name | Type | Mandatory | Description |
460| -- | -- | -- | -- |
461| callback | Callback\<[RichEditorChangeValue](#richeditorchangevalue12) , boolean\> | Yes   | [RichEditorChangeValue](#richeditorchangevalue12) indicates the text and image change information. **boolean** indicates whether the current text and images are allowed to be changed. The value **true** means that the text and images are allowed to be changed, and **false** means the opposite. |
462
463### onDidChange<sup>12+</sup>
464
465onDidChange(callback: OnDidChangeCallback)
466
467Invoked after the text or image in the component changes.
468
469This callback is not supported when the **RichEditor** component constructed with [RichEditorStyledStringOptions](#richeditorstyledstringoptions12) is used.
470
471**Atomic service API**: This API can be used in atomic services since API version 12.
472
473**System capability**: SystemCapability.ArkUI.ArkUI.Full
474
475**Parameters** 
476
477| Name | Type | Mandatory | Description |
478| -- | -- | -- | -- |
479| callback | [OnDidChangeCallback](#ondidchangecallback12) | Yes | Content range before and after the text and image change. |
480
481### onCut<sup>12+</sup>
482
483onCut(callback: Callback\<CutEvent\>)
484
485Invoked when text is about to be cut. By default, only plain text can be cut. You can use this method to override the system's default behavior and implement the cutting of text and images.
486
487**Atomic service API**: This API can be used in atomic services since API version 12.
488
489**System capability**: SystemCapability.ArkUI.ArkUI.Full
490
491**Parameters** 
492
493| Name  | Type                                   | Mandatory  | Description       |
494| ----- | --------------------------------------- | ---- | ----------- |
495| callback |Callback\<[CutEvent](#cutevent12)\> | Yes   | Defines a custom cut event. |
496
497### onCopy<sup>12+</sup>
498
499onCopy(callback: Callback\<CopyEvent\>)
500
501Invoked when text is about to be copied. By default, only plain text can be copied. You can use this method to override the system's default behavior and implement the copying of text and images.
502
503**Atomic service API**: This API can be used in atomic services since API version 12.
504
505**System capability**: SystemCapability.ArkUI.ArkUI.Full
506
507**Parameters** 
508
509| Name  | Type                                   | Mandatory  | Description       |
510| ----- | --------------------------------------- | ---- | ----------- |
511| callback |Callback\<[CopyEvent](#copyevent12)\> | Yes   | User copy event. |
512
513## RichEditorInsertValue
514
515Describes the text to be inserted.
516
517
518
519**System capability**: SystemCapability.ArkUI.ArkUI.Full
520
521| Name          | Type    | Mandatory  | Description        |
522| ------------ | ------ | ---- | ---------- |
523| insertOffset | number | Yes   | Offset of the text to be inserted.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
524| insertValue  | string | Yes   | Content of the text to be inserted.<br>**Atomic service API**: This API can be used in atomic services since API version 11. |
525| previewText<sup>12+</sup> | string | No   | Content of the preview text to be inserted.<br> **Atomic service API**: This API can be used in atomic services since API version 12.|
526
527
528## RichEditorDeleteValue
529
530Provides information about the delete operation and the deleted content.
531
532**Atomic service API**: This API can be used in atomic services since API version 11.
533
534**System capability**: SystemCapability.ArkUI.ArkUI.Full
535
536| Name                   | Type                                      | Mandatory  | Description                 |
537| --------------------- | ---------------------------------------- | ---- | ------------------- |
538| offset                | number                                   | Yes   | Offset of the deleted content.         |
539| direction             | [RichEditorDeleteDirection](#richeditordeletedirection) | Yes   | Direction of the delete operation.           |
540| length                | number                                   | Yes   | Length of the deleted content.            |
541| richEditorDeleteSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes   | Information about the deleted text or image span. |
542
543
544## RichEditorDeleteDirection
545
546Enumerates the directions of the delete operation.
547
548**Atomic service API**: This API can be used in atomic services since API version 11.
549
550**System capability**: SystemCapability.ArkUI.ArkUI.Full
551
552| Name      | Description   |
553| -------- | ----- |
554| BACKWARD | Backward. |
555| FORWARD  | Forward. |
556
557
558## RichEditorTextSpanResult
559
560Provides the text span information.
561
562**System capability**: SystemCapability.ArkUI.ArkUI.Full
563
564| Name                           | Type                                      | Mandatory  | Description                    |
565| ----------------------------- | ---------------------------------------- | ---- | ---------------------- |
566| spanPosition                  | [RichEditorSpanPosition](#richeditorspanposition) | Yes   | Span position.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
567| value                         | string                                   | Yes   | Text span content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
568| textStyle                     | [RichEditorTextStyleResult](#richeditortextstyleresult) | Yes   | Text span style.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
569| offsetInSpan                  | [number, number]                         | Yes   | Start and end positions of the valid content in the text span.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
570| valueResource<sup>11+</sup>   | [Resource](ts-types.md#resource)         | No   | Content of the **\<SymbolSpan>** component.<br>**Atomic service API**: This API can be used in atomic services since API version 12.       |
571| SymbolSpanStyle<sup>11+</sup> | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11) | No   | Style of the **\<SymbolSpan>** component.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
572| paragraphStyle<sup>12+</sup>  | [RichEditorParagraphStyle](#richeditorparagraphstyle11)  | No  | Paragraph style.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
573| previewText<sup>12+</sup>      | string                                   | No   | Content of the preview text.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
574
575
576## RichEditorSpanPosition
577
578Provides the span position information.
579
580**Atomic service API**: This API can be used in atomic services since API version 11.
581
582**System capability**: SystemCapability.ArkUI.ArkUI.Full
583
584| Name       | Type              | Mandatory  | Description                         |
585| --------- | ---------------- | ---- | --------------------------- |
586| spanIndex | number           | Yes   | Span index.                   |
587| spanRange | [number, number] | Yes   | Start and end positions of the span content in the **RichEditor** component. |
588
589## RichEditorSpanType
590
591Provides the span type information.
592
593**Atomic service API**: This API can be used in atomic services since API version 11.
594
595**System capability**: SystemCapability.ArkUI.ArkUI.Full
596
597| Name   | Value    | Description          |
598| ----- | ---- | ------------ |
599| TEXT  | 0 | Text span.  |
600| IMAGE | 1 | Image span.  |
601| MIXED | 2 | Mixed span, which contains both text and imagery. |
602
603## RichEditorTextStyleResult
604
605Provides the text span style information returned by the backend.
606
607**System capability**: SystemCapability.ArkUI.ArkUI.Full
608
609| Name        | Type                                      | Mandatory  | Description          |
610| ---------- | ---------------------------------------- | ---- | ------------ |
611| fontColor  | [ResourceColor](ts-types.md#resourcecolor) | Yes   | Font color.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
612| fontSize   | number                                   | Yes   | Font size. The default unit is fp.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
613| fontStyle  | [FontStyle](ts-appendix-enums.md#fontstyle) | Yes   | Font style.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
614| fontWeight | number                                   | Yes   | Font weight.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
615| fontFamily | string                                   | Yes   | Font family.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
616| decoration | [DecorationStyleResult](ts-universal-styled-string.md#decorationstyleresult) | Yes   | Text decorative line.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
617| lineHeight<sup>12+</sup> | number       | No   | Line height. The default unit is fp.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
618| letterSpacing<sup>12+</sup>| number       | No   | Letter spacing. The default unit is fp.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
619| fontFeature<sup>12+</sup> | string | No | Font feature.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
620
621>  **NOTE**
622>
623>  While **fontWeight** in **RichEditorTextStyle** sets the font weight,
624>  **fontWeight** in **RichEditorTextStyleResult** returns the set font weight after conversion to digits.
625>  The table below lists the conversion mappings.
626>
627>  | fontWeight in RichEditorTextStyle | fontWeight in RichEditorTextStyleResult |
628>  | ---- | ----------------------------------- |
629>  | 100   | 0 |
630>  | 200   | 1 |
631>  | 300   | 2 |
632>  | 400   | 3 |
633>  | 500   | 4 |
634>  | 600   | 5 |
635>  | 700   | 6 |
636>  | 800   | 7 |
637>  | 900   | 8 |
638>  | Lighter   | 12 |
639>  | Normal   | 10 |
640>  | Regular   | 14 |
641>  | Medium   | 13 |
642>  | Bold   | 9 |
643>  | Bolder   | 11 |
644>
645>  The conversion mappings between the **fontWeight** parameters in **RichEditorSymbolSpanStyle** and **RichEditorSymbolSpanStyleResult**
646>  are the same as those between the **fontWeight** parameters in **RichEditorTextStyle** and **RichEditorTextStyleResult**.
647
648## RichEditorSymbolSpanStyleResult<sup>11+</sup>
649
650Provides the symbol span style information returned by the backend.
651
652**Atomic service API**: This API can be used in atomic services since API version 12.
653
654**System capability**: SystemCapability.ArkUI.ArkUI.Full
655
656| Name | Type | Mandatory | Description                              |
657| ------ | -------- | ---- | -------------------------------------- |
658| fontColor | Array\<[ResourceColor](ts-types.md#resourcecolor)\> | No | Color of the symbol span.<br> Default value: depending on the rendering strategy |
659| fontSize | number \| string \| [Resource](ts-types.md#resource) | No | Size of the symbol span. The default unit is fp.<br>The default value follows the theme.|
660| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No | Weight of the symbol span.<br>For the number type, the value ranges from 100 to 900, at an interval of 100. A larger value indicates a heavier font weight. The default value is **400**.<br>For the string type, only strings of the number type are supported, for example, **"400"**, **"bold"**, **"bolder"**, **"lighter"**, **"regular"**, and **"medium"**, which correspond to the enumerated values in **FontWeight**.<br>Default value: **FontWeight.Normal**|
661| renderingStrategy | [SymbolRenderingStrategy](ts-appendix-enums.md#symbolrenderingstrategy11)	| No | Rendering strategy of the symbol span.<br>Default value: **SymbolRenderingStrategy.SINGLE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_folder_badge_plus** supports the **MULTIPLE_COLOR** and **MULTIPLE_OPACITY** modes.|
662| effectStrategy | [SymbolEffectStrategy](ts-appendix-enums.md#symboleffectstrategy11)	| No | Effect strategy of the symbol span.<br>Default value: **SymbolEffectStrategy.NONE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_wifi** supports the hierarchical effect.|
663
664## RichEditorImageSpanResult
665
666Provides the image information returned by the backend.
667
668**Atomic service API**: This API can be used in atomic services since API version 11.
669
670**System capability**: SystemCapability.ArkUI.ArkUI.Full
671
672| Name              | Type                                                               | Mandatory | Description              |
673|------------------|-------------------------------------------------------------------|-----|------------------|
674| spanPosition     | [RichEditorSpanPosition](#richeditorspanposition)                 | Yes  | Span position.|
675| valuePixelMap    | [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7)                    | No  | Image content.|
676| valueResourceStr | [ResourceStr](ts-types.md#resourcestr)                            | No  | Image resource ID.|
677| imageStyle       | [RichEditorImageSpanStyleResult](#richeditorimagespanstyleresult) | Yes | Image style.|
678| offsetInSpan     | [number, number] | Yes | Start and end positions of the image in the span.|
679
680## RichEditorImageSpanStyleResult
681
682Provides the image span style information returned by the backend.
683
684**System capability**: SystemCapability.ArkUI.ArkUI.Full
685
686| Name           | Type                                      | Mandatory  | Description       |
687| ------------- | ---------------------------------------- | ---- | --------- |
688| size          | [number, number]                         | Yes   | Width and height of the image, in px. Default value: varies by the value of **objectFit**. If the value of **objectFit** is **Cover**, the image height is the component height minus the top and bottom paddings, and the image width is the component width minus the left and right paddings.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
689| verticalAlign | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | Yes   | Vertical alignment mode of the image.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
690| objectFit     | [ImageFit](ts-appendix-enums.md#imagefit) | Yes   | Scale mode of the image.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
691| layoutStyle<sup>12+</sup> | [RichEditorLayoutStyle](#richeditorlayoutstyle11)     | No  | Image layout style. |
692
693## RichEditorLayoutStyle<sup>11+</sup> 
694
695**Atomic service API**: This API can be used in atomic services since API version 12.
696
697**System capability**: SystemCapability.ArkUI.ArkUI.Full
698
699|Name	|Type	|Mandatory|	Description|
700| -------------  | -----------------------            | ---- | ------------------------------------------------------------ |
701|margin	         |  [Dimension](ts-types.md#dimension10) \| [Margin](ts-types.md#margin)	                       |  No |	Margins in different directions of the component.<br>When the parameter is of the **Dimension** type, the four margins take effect.|
702|borderRadius	   |  [Dimension](ts-types.md#dimension10) \| [BorderRadiuses](ts-types.md#borderradiuses9)  |  No |	Radius of the rounded corners of the component.<br>If of the **Dimension** type, this parameter cannot be set in percentage.|
703
704## RichEditorOptions
705
706Defines the options for initializing the **RichEditor** component.
707
708**Atomic service API**: This API can be used in atomic services since API version 11.
709
710**System capability**: SystemCapability.ArkUI.ArkUI.Full
711
712| Name        | Type                                      | Mandatory  | Description     |
713| ---------- | ---------------------------------------- | ---- | ------- |
714| controller | [RichEditorController](#richeditorcontroller) | Yes   | Controller for the **RichEditor** component. |
715
716## RichEditorStyledStringOptions<sup>12+</sup>
717
718Defines the options for initializing the **RichEditor** component.
719
720**Atomic service API**: This API can be used in atomic services since API version 12.
721
722**System capability**: SystemCapability.ArkUI.ArkUI.Full
723
724| Name        | Type                                      | Mandatory  | Description     |
725| ---------- | ---------------------------------------- | ---- | ------- |
726| controller | [RichEditorStyledStringController](#richeditorstyledstringcontroller12) | Yes   | Controller for the **RichEditor** component. |
727
728## SelectionOptions<sup>12+</sup>
729
730Defines options for **setSelection**.
731
732**Atomic service API**: This API can be used in atomic services since API version 12.
733
734**System capability**: SystemCapability.ArkUI.ArkUI.Full
735
736| Name        | Type                                      | Mandatory  | Description     |
737| ---------- | ---------------------------------------- | ---- | ------- |
738| menuPolicy | [MenuPolicy](ts-appendix-enums.md#menupolicy12) | No   | Menu display policy. |
739
740## TextDataDetectorConfig<sup>11+</sup>
741
742Provides the text recognition configuration.
743
744**System capability**: SystemCapability.ArkUI.ArkUI.Full
745
746| Name        | Type                                                                   | Mandatory  | Description     |
747| ---------- |-----------------------------------------------------------------------| ---- | ------- |
748| types | [TextDataDetectorType](ts-appendix-enums.md#textdatadetectortype11)[] | Yes   | Entity types for text recognition. Values **null** and **[]** indicate that all types of entities can be recognized. |
749| onDetectResultUpdate | (result: string) =&gt; void                            | No   | Callback invoked when text recognition succeeds.<br>**result**: text recognition result, in JSON format. |
750
751## RichEditorChangeValue<sup>12+</sup>
752
753**Atomic service API**: This API can be used in atomic services since API version 12.
754
755| Name                   | Type                                      | Mandatory  | Description                 |
756| --------------------- | ---------------------------------------- | ---- | ------------------- |
757| rangeBefore | [TextRange](ts-text-common.md#textrange12) | Yes   | Information about the text span before the change. |
758| replacedSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)> | Yes   | Information about the text span after the change. |
759| replacedImageSpans | Array<[RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes   | Information about the image span after the change. |
760| replacedSymbolSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult)> | Yes   | Information about the symbol span after the change. |
761
762## RichEditorBaseController<sup>12+</sup>
763
764Represents the base class of the **RichEditor** component controller.
765
766### getCaretOffset<sup>12+</sup>
767
768getCaretOffset(): number
769
770Obtains the current cursor position.
771
772**Atomic service API**: This API can be used in atomic services since API version 11.
773
774**System capability**: SystemCapability.ArkUI.ArkUI.Full
775
776**Return value**
777
778| Type    | Description       |
779| ------ | --------- |
780| number | Cursor position. |
781
782### setCaretOffset<sup>12+</sup>
783
784setCaretOffset(offset: number): boolean
785
786Sets the cursor position.
787
788**Atomic service API**: This API can be used in atomic services since API version 11.
789
790**System capability**: SystemCapability.ArkUI.ArkUI.Full
791
792**Parameters**
793
794| Name   | Type  | Mandatory  | Description                |
795| ------ | ------ | ---- | -------------------- |
796| offset | number | Yes   | Offset of the cursor. If it exceeds the range of all content, the setting will fail. |
797
798**Return value**
799
800| Type     | Description       |
801| ------- | --------- |
802| boolean | Whether the cursor position is set successfully. |
803
804### closeSelectionMenu<sup>12+</sup>
805
806closeSelectionMenu(): void
807
808Closes the custom or default context menu on selection.
809
810**System capability**: SystemCapability.ArkUI.ArkUI.Full
811
812
813### getTypingStyle<sup>12+</sup>
814
815getTypingStyle(): RichEditorTextStyle
816
817Obtains the preset typing style.
818
819**Atomic service API**: This API can be used in atomic services since API version 12.
820
821**System capability**: SystemCapability.ArkUI.ArkUI.Full
822
823**Return value**
824
825| Type                                      | Description     |
826| ---------------------------------------- | ------- |
827| [RichEditorTextStyle](#richeditortextstyle) | Preset typing style. |
828
829### setTypingStyle<sup>12+</sup>
830
831setTypingStyle(value: RichEditorTextStyle): void
832
833Sets the typing style.
834
835**Atomic service API**: This API can be used in atomic services since API version 12.
836
837**System capability**: SystemCapability.ArkUI.ArkUI.Full
838
839**Parameters**
840
841| Name  | Type                                    | Mandatory  | Description |
842| ----- | ---------------------------------------- | ---- | ----- |
843| value | [RichEditorTextStyle](#richeditortextstyle) | Yes   | Typing style to set. |
844
845### setSelection<sup>12+</sup>
846
847setSelection(selectionStart: number, selectionEnd: number, options?: SelectionOptions): void
848
849Sets the range of content selection. The selected content is highlighted.
850
851If both **selectionStart** and **selectionEnd** are set to **-1**, all text is selected.
852
853If this API is called when the text box is not focused, the selected effect is not displayed.
854
855Since API version 12, on 2-in-1 devices, regardless of the value of **options**, calling the **setSelection** API will not display the menu. In addition, if there is already a menu present within the component, calling the **setSelection** API will close the menu.
856
857On non-2-in-1 devices, when **options** is set to **MenuPolicy.DEFAULT**, the following rules apply:
858
8591. If the component has a selection handle menu, calling the API will not close the menu, and the menu position will be adjusted.
860
8612. If the component has a menu without a selection handle, calling the API will not close the menu, and the menu position will remain unchanged.
862
8633. If there is no menu within the component, calling the API will not display the menu.
864
865**Atomic service API**: This API can be used in atomic services since API version 12.
866
867**System capability**: SystemCapability.ArkUI.ArkUI.Full
868
869**Parameters**
870
871| Name           | Type  | Mandatory  | Description   |
872| -------------- | ------ | ---- | ------- |
873| selectionStart | number | Yes   | Start position of the text selection. |
874| selectionEnd   | number | Yes   | End position of the text selection. |
875| options<sup>12+</sup>   | [SelectionOptions](#selectionoptions12) | No   | Configuration of options. |
876
877### isEditing<sup>12+</sup>
878
879isEditing(): boolean
880
881Obtains the editing state of this **RichEditor** component.
882
883**Atomic service API**: This API can be used in atomic services since API version 12.
884
885**System capability**: SystemCapability.ArkUI.ArkUI.Full
886
887**Return value**
888
889| Type   | Description                         |
890| ------- | ----------------------------- |
891| boolean | Editing state. The value **true** indicates the editing state, and **false** indicates the non-editing state. |
892
893### stopEditing<sup>12+</sup>
894
895stopEditing(): void
896
897Exits the editing state.
898
899**Atomic service API**: This API can be used in atomic services since API version 12.
900
901**System capability**: SystemCapability.ArkUI.ArkUI.Full
902
903### getLayoutManager<sup>12+</sup>
904
905getLayoutManager(): LayoutManager
906
907Obtains a **LayoutManager** object.
908
909**System capability**: SystemCapability.ArkUI.ArkUI.Full
910
911**Return value**
912
913| Type                                      | Description     |
914| ---------------------------------------- | ------- |
915| [LayoutManager](ts-text-common.md#LayoutManager12) | **LayoutManager** object. |
916
917### getPreviewText<sup>12+</sup>
918
919getPreviewText(): PreviewText
920
921Obtains the preview text.
922
923**System capability**: SystemCapability.ArkUI.ArkUI.Full
924
925**Return value**
926
927| Type                                      | Description     |
928| ---------------------------------------- | ------- |
929| [PreviewText](#previewtext12) | Preview text. |
930
931## RichEditorController
932
933Implements the **RichEditor** component controller. Inherits from [RichEditorBaseController](#richeditorbasecontroller12).
934
935### Objects to Import
936
937```
938controller: RichEditorController = new RichEditorController()
939```
940
941### getCaretOffset
942
943getCaretOffset(): number
944
945Obtains the current cursor position.
946
947**Atomic service API**: This API can be used in atomic services since API version 11.
948
949**System capability**: SystemCapability.ArkUI.ArkUI.Full
950
951**Return value**
952
953| Type    | Description       |
954| ------ | --------- |
955| number | Cursor position. |
956
957### setCaretOffset
958
959setCaretOffset(offset: number): boolean
960
961Sets the cursor position.
962
963**Atomic service API**: This API can be used in atomic services since API version 11.
964
965**System capability**: SystemCapability.ArkUI.ArkUI.Full
966
967**Parameters**
968
969| Name   | Type  | Mandatory  | Description                |
970| ------ | ------ | ---- | -------------------- |
971| offset | number | Yes   | Offset of the cursor. If the value is out of the text range, the setting fails. |
972
973**Return value**
974
975| Type     | Description       |
976| ------- | --------- |
977| boolean | Whether the cursor position is set successfully. |
978
979### addTextSpan
980
981addTextSpan(value: string, options?: RichEditorTextSpanOptions): number
982
983Adds a text span. If the cursor in the component is blinking, the cursor position is updated to be after the inserted text span.
984
985**Atomic service API**: This API can be used in atomic services since API version 11.
986
987**System capability**: SystemCapability.ArkUI.ArkUI.Full
988
989**Parameters**
990
991| Name    | Type                                    | Mandatory  | Description |
992| ------- | ---------------------------------------- | ---- | ----- |
993| value   | string                                   | Yes   | Text content. |
994| options | [RichEditorTextSpanOptions](#richeditortextspanoptions) | No   | Text options. |
995
996**Return value**
997
998| Type    | Description                  |
999| ------ | -------------------- |
1000| number | Position of the added text span. |
1001
1002### addImageSpan
1003
1004addImageSpan(value: PixelMap | ResourceStr, options?: RichEditorImageSpanOptions): number
1005
1006Adds an image span. If the cursor in the component is blinking, the cursor position is updated to be after the inserted image span.
1007
1008**Atomic service API**: This API can be used in atomic services since API version 11.
1009
1010**System capability**: SystemCapability.ArkUI.ArkUI.Full
1011
1012**Parameters**
1013
1014| Name    | Type                                    | Mandatory  | Description |
1015| ------- | ---------------------------------------- | ---- | ----- |
1016| value   | [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7)\|[ResourceStr](ts-types.md#resourcestr) | Yes   | Image content. |
1017| options | [RichEditorImageSpanOptions](#richeditorimagespanoptions) | No   | Image options. |
1018
1019**Return value**
1020
1021| Type    | Description                  |
1022| ------ | -------------------- |
1023| number | Position of the added image span. |
1024
1025### addBuilderSpan<sup>11+</sup>
1026
1027addBuilderSpan(value: CustomBuilder, options?: RichEditorBuilderSpanOptions): number
1028
1029> **NOTE**
1030>
1031> - This API adds a builder span to take up space in the layout. It calls the system **measure** method to calculate the actual length, width, and position.
1032> - You can use [RichEditorBuilderSpanOptions](#richeditorbuilderspanoptions11) to set the index of the builder in the **RichEditor** component (with one character as the unit).
1033> - This builder span is not focusable. It supports dragging and some universal attributes. Its capabilities regarding placeholder and deletion are equivalent to the image span, and its length is considered as one character.
1034> - The builder span does not allow for custom menus set through [bindSelectionMenu](#attributes).
1035> - The information about the builder span cannot be obtained through [getSpans](#getspans), [getSelection](#getselection11), [onSelect](#events), or [aboutToDelete](#events).
1036> - The builder span cannot be updated using [updateSpanStyle](#updatespanstyle) or [updateParagraphStyle](#updateparagraphstyle11).
1037> - Copying or pasting the builder span does not take effect.
1038> - The layout constraints of the builder span are passed in from the **RichEditor** component. If the size of the outermost component in the builder span is not set, the size of the **RichEditor** is used as the value of **maxSize**.
1039> - The gesture event mechanism of the builder span is the same as the universal gesture event mechanism. If transparent transmission is not set in the builder, only the child components in the builder respond.
1040> - If the cursor in the component is blinking, the cursor position is updated to be after the inserted image span.
1041
1042The following universal attributes are supported: [size](ts-universal-attributes-size.md#size), [padding](ts-universal-attributes-size.md#padding), [margin](ts-universal-attributes-size.md#margin), [aspectRatio](ts-universal-attributes-layout-constraints.md#aspectratio), [borderStyle](ts-universal-attributes-border.md#borderstyle), [borderWidth](ts-universal-attributes-border.md#borderwidth), [borderColor](ts-universal-attributes-border.md#bordercolor), [borderRadius](ts-universal-attributes-border.md#borderradius), [backgroundColor](ts-universal-attributes-background.md#backgroundcolor), [backgroundBlurStyle](ts-universal-attributes-background.md#backgroundblurstyle9), [opacity](ts-universal-attributes-opacity.md), [blur](ts-universal-attributes-image-effect.md#blur), [backdropBlur](ts-universal-attributes-image-effect.md#backdropblur), [shadow](ts-universal-attributes-image-effect.md#shadow), [grayscale](ts-universal-attributes-image-effect.md#grayscale), [brightness](ts-universal-attributes-image-effect.md#brightness), [saturate](ts-universal-attributes-image-effect.md#saturate),
1043[contrast](ts-universal-attributes-image-effect.md#contrast), [invert](ts-universal-attributes-image-effect.md#invert), [sepia](ts-universal-attributes-image-effect.md#sepia), [hueRotate](ts-universal-attributes-image-effect.md#huerotate), [colorBlend](ts-universal-attributes-image-effect.md#colorblend7), [linearGradientBlur](ts-universal-attributes-image-effect.md#lineargradientblur12), [clip](ts-universal-attributes-sharp-clipping.md#clip), [mask](ts-universal-attributes-sharp-clipping.md#mask), [foregroundBlurStyle](ts-universal-attributes-foreground-blur-style.md#foregroundblurstyle), [accessibilityGroup](ts-universal-attributes-accessibility.md#accessibilitygroup), [accessibilityText](ts-universal-attributes-accessibility.md#accessibilitytext), [accessibilityDescription](ts-universal-attributes-accessibility.md#accessibilitydescription), [accessibilityLevel](ts-universal-attributes-accessibility.md#accessibilitylevel), [sphericalEffect](ts-universal-attributes-image-effect.md#sphericaleffect12), [lightUpEffect](ts-universal-attributes-image-effect.md#lightupeffect12), [pixelStretchEffect](ts-universal-attributes-image-effect.md#pixelstretcheffect12)
1044
1045**Atomic service API**: This API can be used in atomic services since API version 12.
1046
1047**System capability**: SystemCapability.ArkUI.ArkUI.Full
1048
1049**Parameters**
1050
1051| Name    | Type                                    | Mandatory  | Description      |
1052| ------- | ---------------------------------------- | ---- | ---------- |
1053| value   | [CustomBuilder](ts-types.md#custombuilder8) | Yes   | Custom component.    |
1054| options | [RichEditorBuilderSpanOptions](#richeditorbuilderspanoptions11) | No   | Builder options. |
1055
1056**Return value**
1057
1058| Type    | Description                    |
1059| ------ | ---------------------- |
1060| number | Position of the added builder span. |
1061
1062### addSymbolSpan<sup>11+</sup>
1063
1064addSymbolSpan(value: Resource, options?: RichEditorSymbolSpanOptions ): number
1065
1066Adds a symbol image. If the cursor in the component is blinking, the cursor position is updated to be after the inserted symbol span.
1067
1068Currently, gestures, copying, and dragging are not supported.
1069
1070**Atomic service API**: This API can be used in atomic services since API version 12.
1071
1072**System capability**: SystemCapability.ArkUI.ArkUI.Full
1073
1074**Parameters**
1075
1076| Name    | Type                                    | Mandatory  | Description |
1077| ------- | ---------------------------------------- | ---- | ----- |
1078| value   | [Resource](ts-types.md#resource)         | Yes   | Content of the symbol span. |
1079| options | [RichEditorSymbolSpanOptions](#richeditorsymbolspanoptions11) | No   | Options of the symbol span. |
1080
1081**Return value**
1082
1083| Type    | Description                   |
1084| ------ | --------------------- |
1085| number | Position of the added symbol span. |
1086
1087### getTypingStyle<sup>11+</sup>
1088
1089getTypingStyle(): RichEditorTextStyle
1090
1091Obtains the preset typing style.
1092
1093**Atomic service API**: This API can be used in atomic services since API version 12.
1094
1095**System capability**: SystemCapability.ArkUI.ArkUI.Full
1096
1097**Return value**
1098
1099| Type                                      | Description     |
1100| ---------------------------------------- | ------- |
1101| [RichEditorTextStyle](#richeditortextstyle) | Preset typing style. |
1102
1103### setTypingStyle<sup>11+</sup>
1104
1105setTypingStyle(value: RichEditorTextStyle): void
1106
1107Sets the typing style.
1108
1109When the default value (**undefined**/**null**) is used or this API is not called:<br>
1110- When users type into a **RichEditor** component with no text content using the keyboard, the typed text is displayed in the default style. For the default style, see [RichEditorTextStyle](#richeditortextstyle).<br>
1111- When users type into a **RichEditor** component with existing text content using the keyboard, the typed text follows the style of the preceding text and is not displayed in the default style.
1112
1113When a non-default value is used:<br>
1114- When users type into the **RichEditor** component using the keyboard, the text is displayed in the style set by you. If there are attributes in the preset style that have not been set, they use default values of [RichEditorTextStyle](#richeditortextstyle).
1115
1116**Atomic service API**: This API can be used in atomic services since API version 12.
1117
1118**System capability**: SystemCapability.ArkUI.ArkUI.Full
1119
1120**Parameters**
1121
1122| Name  | Type                                    | Mandatory  | Description |
1123| ----- | ---------------------------------------- | ---- | ----- |
1124| value | [RichEditorTextStyle](#richeditortextstyle) | Yes   | Typing style to set. |
1125
1126### updateSpanStyle
1127
1128updateSpanStyle(value: RichEditorUpdateTextSpanStyleOptions | RichEditorUpdateImageSpanStyleOptions | RichEditorUpdateSymbolSpanStyleOptions): void
1129
1130Updates the text, image, or symbol span style.<br>If only part of a span is updated, the span is split into multiple spans based on the updated part and the non-updated part.
1131
1132Calling this API will not close the custom context menu on selection by default.
1133
1134**Atomic service API**: This API can be used in atomic services since API version 11.
1135
1136**System capability**: SystemCapability.ArkUI.ArkUI.Full
1137
1138**Parameters**
1139
1140| Name | Type | Mandatory | Description                              |
1141| ------ | -------- | ---- | -------------------------------------- |
1142| value | [RichEditorUpdateTextSpanStyleOptions](#richeditorupdatetextspanstyleoptions) \| [RichEditorUpdateImageSpanStyleOptions](#richeditorupdateimagespanstyleoptions) \| [RichEditorUpdateSymbolSpanStyleOptions](#richeditorupdatesymbolspanstyleoptions11)<sup>11+</sup> | Yes | Style options of the text, image, or symbol span. |
1143
1144### updateParagraphStyle<sup>11+</sup>
1145
1146updateParagraphStyle(value: RichEditorParagraphStyleOptions): void
1147
1148Updates the paragraph style.
1149
1150**Atomic service API**: This API can be used in atomic services since API version 12.
1151
1152**System capability**: SystemCapability.ArkUI.ArkUI.Full
1153
1154**Parameters**
1155
1156| Name   | Type                                      | Mandatory  | Description        |
1157| ----- | ---------------------------------------- | ---- | ---------- |
1158| value | [RichEditorParagraphStyleOptions](#richeditorparagraphstyleoptions11) | Yes   | Information about the paragraph style. |
1159
1160### getSpans
1161
1162getSpans(value?: RichEditorRange): Array<RichEditorTextSpanResult| RichEditorImageSpanResult>
1163
1164Obtains span information.
1165
1166**Atomic service API**: This API can be used in atomic services since API version 11.
1167
1168**System capability**: SystemCapability.ArkUI.ArkUI.Full
1169
1170**Parameters**
1171
1172| Name  | Type                               | Mandatory  | Description       |
1173| ----- | ----------------------------------- | ---- | ----------- |
1174| value | [RichEditorRange](#richeditorrange) | No   | Range of the target span. |
1175
1176**Return value**
1177
1178| Type                                      | Description          |
1179| ---------------------------------------- | ------------ |
1180| Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Text and image span information. |
1181
1182### deleteSpans
1183
1184deleteSpans(value?: RichEditorRange): void
1185
1186Deletes the text and image spans in a specified range.
1187
1188**Atomic service API**: This API can be used in atomic services since API version 11.
1189
1190**System capability**: SystemCapability.ArkUI.ArkUI.Full
1191
1192**Parameters**
1193
1194| Name  | Type                               | Mandatory  | Description               |
1195| ----- | ----------------------------------- | ---- | ------------------- |
1196| value | [RichEditorRange](#richeditorrange) | No   | Range of the target spans. If this parameter is left empty, all text and image spans will be deleted. |
1197
1198### getParagraphs<sup>11+</sup>
1199
1200getParagraphs(value?: RichEditorRange): Array\<RichEditorParagraphResult>
1201
1202Obtains the specified paragraphs.
1203
1204**Atomic service API**: This API can be used in atomic services since API version 12.
1205
1206**System capability**: SystemCapability.ArkUI.ArkUI.Full
1207
1208**Parameters**
1209
1210| Name  | Type                               | Mandatory  | Description      |
1211| ----- | ----------------------------------- | ---- | ---------- |
1212| value | [RichEditorRange](#richeditorrange) | No   | Range of the paragraphs to obtain. |
1213
1214**Return value**
1215
1216| Type                                      | Description      |
1217| ---------------------------------------- | -------- |
1218| Array\<[RichEditorParagraphResult](#richeditorparagraphresult11)> | Information about the selected paragraphs. |
1219
1220### closeSelectionMenu
1221
1222closeSelectionMenu(): void
1223
1224Closes the custom or default context menu on selection.
1225
1226**Atomic service API**: This API can be used in atomic services since API version 11.
1227
1228**System capability**: SystemCapability.ArkUI.ArkUI.Full
1229
1230### setSelection<sup>11+</sup>
1231
1232setSelection(selectionStart: number, selectionEnd: number, options?: SelectionOptions): void
1233
1234Sets the range of the current text selection. The selected text is highlighted.
1235
1236If both **selectionStart** and **selectionEnd** are set to **-1**, all text is selected.
1237
1238If this API is called when the text box is not focused, the selected effect is not displayed.
1239
1240Since API version 12, on 2-in-1 devices, regardless of the value of **options**, calling the **setSelection** API will not display the menu. In addition, if there is already a menu present within the component, calling the **setSelection** API will close the menu.
1241
1242On non-2-in-1 devices, when **options** is set to **MenuPolicy.DEFAULT**, the following rules apply:
1243
12441. If the component has a selection handle menu, calling the API will not close the menu, and the menu position will be adjusted.
1245
12462. If the component has a menu without a selection handle, calling the API will not close the menu, and the menu position will remain unchanged.
1247
12483. If there is no menu within the component, calling the API will not display the menu.
1249
1250For details, see [Example](ohos-arkui-advanced-SelectionMenu.md#example).
1251
1252**Atomic service API**: This API can be used in atomic services since API version 12.
1253
1254**System capability**: SystemCapability.ArkUI.ArkUI.Full
1255
1256**Parameters**
1257
1258| Name           | Type  | Mandatory  | Description   |
1259| -------------- | ------ | ---- | ------- |
1260| selectionStart | number | Yes   | Start position of the text selection. |
1261| selectionEnd   | number | Yes   | End position of the text selection. |
1262| options<sup>12+</sup>   | [SelectionOptions](#selectionoptions12) | No   | Configuration of options. |
1263
1264### getSelection<sup>11+</sup>
1265
1266getSelection(): RichEditorSelection
1267
1268Obtains the selected content. If no text is selected, the information about the span where the caret is located is returned.
1269
1270**Atomic service API**: This API can be used in atomic services since API version 12.
1271
1272**System capability**: SystemCapability.ArkUI.ArkUI.Full
1273
1274**Return value**
1275
1276| Type                                      | Description     |
1277| ---------------------------------------- | ------- |
1278| [RichEditorSelection](#richeditorselection) | Provides information about the selected content. |
1279
1280### fromStyledString<sup>12+</sup>
1281
1282fromStyledString(value: StyledString): Array\<RichEditorSpan>
1283
1284Converts a styled string into a span.
1285
1286**Atomic service API**: This API can be used in atomic services since API version 12.
1287
1288**System capability**: SystemCapability.ArkUI.ArkUI.Full
1289
1290**Parameters**
1291
1292| Name  | Type                               | Mandatory  | Description      |
1293| ----- | ----------------------------------- | ---- | ---------- |
1294| value | [RichEditorRange](#richeditorrange) | No   | Source range. |
1295
1296**Return value**
1297
1298| Type                                      | Description     |
1299| ---------------------------------------- | ------- |
1300| Array<[RichEditorSpan](#richeditorspan12)>  | Text and image span information. |
1301
1302### toStyledString<sup>12+</sup>
1303
1304toStyledString(value: RichEditorRange): StyledString
1305
1306Converts the component content within the given range into a styled string.
1307
1308**Atomic service API**: This API can be used in atomic services since API version 12.
1309
1310**System capability**: SystemCapability.ArkUI.ArkUI.Full
1311
1312**Parameters**
1313
1314| Name  | Type                               | Mandatory  | Description      |
1315| ----- | ----------------------------------- | ---- | ---------- |
1316| value | [RichEditorRange](#richeditorrange) | No   | Source range. |
1317
1318**Return value**
1319
1320| Type                                      | Description      |
1321| ---------------------------------------- | -------- |
1322| [StyledString](ts-universal-styled-string.md#styledstring) | Styled string after conversion. |
1323
1324## RichEditorStyledStringController<sup>12+</sup>
1325
1326Represents the controller of the **RichEditor** component constructed using the styled string. Inherits from [RichEditorBaseController](#richeditorbasecontroller12).
1327
1328### Objects to Import
1329
1330```
1331controller: RichEditorStyledStringController = new RichEditorStyledStringController()
1332```
1333
1334### getSelection<sup>12+</sup>
1335
1336getSelection(): RichEditorRange
1337
1338Obtains the current selection range of the **RichEditor** component.
1339
1340**Atomic service API**: This API can be used in atomic services since API version 12.
1341
1342**System capability**: SystemCapability.ArkUI.ArkUI.Full
1343
1344**Return value**
1345
1346| Type                                      | Description     |
1347| ---------------------------------------- | ------- |
1348| [RichEditorRange](#richeditorrange) | Selection range. |
1349
1350### setStyledString<sup>12+</sup>
1351
1352setStyledString(styledString: StyledString): void
1353
1354Sets the styled string displayed in the **RichEditor** component.
1355
1356**Atomic service API**: This API can be used in atomic services since API version 12.
1357
1358**System capability**: SystemCapability.ArkUI.ArkUI.Full
1359
1360**Parameters**
1361
1362| Name  | Type  | Mandatory  | Description               |
1363| ----- | ------ | ---- | ------------------- |
1364| value | [StyledString](ts-universal-styled-string.md#styledstring) | Yes   | Styled string.<br>**NOTE**<br>The child class [MutableStyledString](ts-universal-styled-string.md#mutablestyledstring) of **StyledString** can also serve as the argument. |
1365
1366### getStyledString<sup>12+</sup>
1367
1368getStyledString(): MutableStyledString;
1369
1370Obtains the styled string displayed in the **RichEditor** component.
1371
1372**Atomic service API**: This API can be used in atomic services since API version 12.
1373
1374**System capability**: SystemCapability.ArkUI.ArkUI.Full
1375
1376**Return value**
1377
1378| Type   | Description                         |
1379| ------- | ----------------------------- |
1380| [MutableStyledString](ts-universal-styled-string.md#mutablestyledstring) | Styled string displayed in the **RichEditor** component. |
1381
1382### onContentChanged<sup>12+</sup>
1383
1384onContentChanged(listener: StyledStringChangedListener): void
1385
1386Register a callback for text content changes, which will be invoked when the text content is changed by the backend program.
1387
1388**Atomic service API**: This API can be used in atomic services since API version 12.
1389
1390**System capability**: SystemCapability.ArkUI.ArkUI.Full
1391
1392**Parameters**
1393
1394| Name  | Type  | Mandatory  | Description               |
1395| ----- | ------ | ---- | ------------------- |
1396| listener | [StyledStringChangedListener](#styledstringchangedlistener12) | Yes   | Callback listener for text content changes. |
1397
1398## RichEditorSelection
1399
1400Provides information about the selected content.
1401
1402**Atomic service API**: This API can be used in atomic services since API version 11.
1403
1404**System capability**: SystemCapability.ArkUI.ArkUI.Full
1405
1406| Name       | Type                                      | Mandatory  | Description     |
1407| --------- | ---------------------------------------- | ---- | ------- |
1408| selection | [number, number]                         | Yes   | Range of the selected.  |
1409| spans     | Array<[RichEditorTextSpanResult](#richeditortextspanresult)\| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes   | Span information. |
1410
1411
1412## RichEditorUpdateTextSpanStyleOptions
1413
1414Defines the text span style options.
1415
1416**Atomic service API**: This API can be used in atomic services since API version 11.
1417
1418**System capability**: SystemCapability.ArkUI.ArkUI.Full
1419
1420| Name       | Type                                      | Mandatory  | Description                             |
1421| --------- | ---------------------------------------- | ---- | ------------------------------- |
1422| start     | number                                   | No   | Start position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used. |
1423| end       | number                                   | No   | End position of the span whose style needs to be updated. If this parameter is left empty or set to a value beyond the range, it indicates infinity. |
1424| textStyle | [RichEditorTextStyle](#richeditortextstyle) | Yes   | Text style.                          |
1425
1426>  **NOTE**
1427>
1428>  If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**.
1429
1430## RichEditorUpdateImageSpanStyleOptions
1431
1432Defines the image span style options.
1433
1434**Atomic service API**: This API can be used in atomic services since API version 11.
1435
1436**System capability**: SystemCapability.ArkUI.ArkUI.Full
1437
1438| Name        | Type                                      | Mandatory  | Description                             |
1439| ---------- | ---------------------------------------- | ---- | ------------------------------- |
1440| start      | number                                   | No   | Start position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used. |
1441| end        | number                                   | No   | End position of the span whose style needs to be updated. If this parameter is left empty or set to a value beyond the range, it indicates infinity. |
1442| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | Yes   | Image style.                          |
1443
1444>  **NOTE**
1445>
1446>  If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**.
1447
1448## RichEditorUpdateSymbolSpanStyleOptions<sup>11+</sup>
1449
1450Defines the symbol span style options.
1451
1452**Atomic service API**: This API can be used in atomic services since API version 12.
1453
1454**System capability**: SystemCapability.ArkUI.ArkUI.Full
1455
1456| Name         | Type                                      | Mandatory  | Description                             |
1457| ----------- | ---------------------------------------- | ---- | ------------------------------- |
1458| start       | number                                   | No   | Start position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used. |
1459| end         | number                                   | No   | End position of the span whose style needs to be updated. If this parameter is left empty or set to a value beyond the range, it indicates infinity. |
1460| symbolStyle | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11) | Yes   | Style of the symbol span.                          |
1461
1462>  **NOTE**
1463>
1464>  If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**.
1465
1466## RichEditorParagraphStyleOptions<sup>11+</sup>
1467
1468Describes the paragraph style options.
1469
1470**Atomic service API**: This API can be used in atomic services since API version 12.
1471
1472**System capability**: SystemCapability.ArkUI.ArkUI.Full
1473
1474| Name   | Type                                      | Mandatory  | Description                                |
1475| ----- | ---------------------------------------- | ---- | ---------------------------------- |
1476| start | number                                   | No   | Start position of the paragraph whose style needs to be updated. If this parameter is left empty or set to a negative value, the value **0** will be used.    |
1477| end   | number                                   | No   | End position of the span whose style needs to be updated. If this parameter is left empty or set to a negative value or a value beyond the range, it indicates infinity. |
1478| style | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | Yes   | Paragraph style.                             |
1479
1480>  **NOTE**
1481>
1482>  Applicable scope of the API: spans involved in the specified range.
1483>  If the value of **start** is greater than that of **end**, the value **0** will be used as **start** and infinity as **end**.
1484
1485
1486## RichEditorParagraphStyle<sup>11+</sup>
1487
1488Describes the paragraph style.
1489
1490**Atomic service API**: This API can be used in atomic services since API version 12.
1491
1492**System capability**: SystemCapability.ArkUI.ArkUI.Full
1493
1494| Name           | Type                                      | Mandatory  | Description                |
1495| ------------- | ---------------------------------------- | ---- | ------------------ |
1496| textAlign     | [TextAlign](ts-appendix-enums.md#textalign) | No   | Horizontal alignment mode of the text. <br>Default value: **TextAlign.START**<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1497| leadingMargin | [Dimension](ts-types.md#dimension10) \| [LeadingMarginPlaceholder](#leadingmarginplaceholder11) | No   | Indent of the paragraph. It has no effect if the paragraph starts with an image or builder span. If of the **Dimension** type, this parameter cannot be set in percentage. Default value: **{"size":["0.00px","0.00px"]}**<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1498| wordBreak<sup>12+</sup> |  [WordBreak](ts-appendix-enums.md#wordbreak11) | No   | Word break rule.<br>Default value: **WordBreak.BREAK_WORD** |
1499| lineBreakStrategy<sup>12+</sup> | [LineBreakStrategy](ts-appendix-enums.md#linebreakstrategy12) | No | Line break rule.<br>Default value: **LineBreakStrategy.GREEDY**<br>This parameter takes effect when **wordBreak** is not set to **breakAll**. Hyphens are not supported. |
1500
1501## LeadingMarginPlaceholder<sup>11+</sup>
1502
1503Describes the leading margin placeholder, which dictates the distance between the left edges of the paragraph and the component.
1504
1505**System capability**: SystemCapability.ArkUI.ArkUI.Full
1506
1507| Name      | Type                                      | Mandatory  | Description            |
1508| -------- | ---------------------------------------- | ---- | -------------- |
1509| pixelMap | [PixelMap](../../apis-image-kit/js-apis-image.md#pixelmap7) | Yes   | Image content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1510| size     | \[[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)\] | Yes   | Image size. This parameter cannot be set in percentage. |
1511
1512## RichEditorParagraphResult<sup>11+</sup>
1513
1514Describes the returned paragraph information.
1515
1516**Atomic service API**: This API can be used in atomic services since API version 12.
1517
1518**System capability**: SystemCapability.ArkUI.ArkUI.Full
1519
1520| Name   | Type                                      | Mandatory  | Description     |
1521| ----- | ---------------------------------------- | ---- | ------- |
1522| style | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | Yes   | Paragraph style.  |
1523| range | \[number, number\]                       | Yes   | Start and end positions of the paragraph. |
1524
1525## RichEditorTextSpanOptions
1526
1527Describes the options for adding a text span.
1528
1529**System capability**: SystemCapability.ArkUI.ArkUI.Full
1530
1531| Name                          | Type                                      | Mandatory  | Description                        |
1532| ---------------------------- | ---------------------------------------- | ---- | -------------------------- |
1533| offset                       | number                                   | No   | Position of the text span to be added. If this parameter is omitted, the paragraph is added to the end of all content.<br>If the value specified is less than 0, the paragraph is placed at the beginning of all content. If the value is greater than the length of all content, the paragraph is placed at the end of all content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1534| style                        | [RichEditorTextStyle](#richeditortextstyle) | No   | Style of the text span to be added. If this parameter is left empty, the default text style will be used.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1535| paragraphStyle<sup>11+</sup> | [RichEditorParagraphStyle](#richeditorparagraphstyle11) | No   | Paragraph style.<br>**Atomic service API**: This API can be used in atomic services since API version 12. |
1536| gesture<sup>11+</sup>        | [RichEditorGesture](#richeditorgesture11) | No   | Behavior-triggered callback. If this parameter is left empty, only the default system behavior is supported.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1537
1538## RichEditorTextStyle
1539
1540Provides the text style information.
1541
1542**System capability**: SystemCapability.ArkUI.ArkUI.Full
1543
1544| Name                      | Type                                      | Mandatory  | Description                                      |
1545| ------------------------ | ---------------------------------------- | ---- | ---------------------------------------- |
1546| fontColor                | [ResourceColor](ts-types.md#resourcecolor) | No   | Font color.<br> Default value: **$r('sys.color.font_primary')**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1547| fontSize                 | [Length](ts-types.md#length) \| number            | No   | Font size. If **Length** is of the number type, the unit fp is used. The default value is **16**. The value cannot be a percentage. If the font size is set to 0, the default font size is used.<br>**Widget capability**: This API can be used in ArkTS widgets since API version 9.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1548| fontStyle                | [FontStyle](ts-appendix-enums.md#fontstyle) | No   | Font style.<br>Default value: **FontStyle.Normal**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1549| fontWeight               | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No   | Font weight.<br>For the number type, the value ranges from 100 to 900, at an interval of 100. A larger value indicates a heavier font weight. The default value is **400**.<br>For the string type, only strings of the number type are supported, for example, **"400"**, **"bold"**, **"bolder"**, **"lighter"**, **"regular"**, and **"medium"**, which correspond to the enumerated values in **FontWeight**.<br>Default value: **FontWeight.Normal**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1550| fontFamily               | [ResourceStr](ts-types.md#resourcestr) | No   | Font family. The HarmonyOS Sans font and [register custom fonts](../js-apis-font.md) are supported.<br>Default font: **'HarmonyOS Sans'**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1551| decoration               | [DecorationStyleInterface](ts-universal-styled-string.md#decorationstyleinterface) | No   | Style and color of the text decorative line.<br>Default value of **type**: **TextDecorationType.None**<br>Default value of **color**: same as the font color<br>Default value of **style**: **TextDecorationStyle.SOLID**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1552| textShadow<sup>11+</sup> | [ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions) \| Array&lt;[ShadowOptions](ts-universal-attributes-image-effect.md#shadowoptions)>  | No   | Text shadow. It supports input parameters in an array to implement multiple text shadows.<br>**NOTE**<br>Only the shadow blur radius, shadow color, and shadow offset can be set.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1553| lineHeight<sup>12+</sup>    | number \| string \| [Resource](ts-types.md#resource) | No    |Text line height. If the value is less than or equal to 0, the line height is not limited and the font size is adaptive. If the value is of the number type, the unit fp is used. The value cannot be a percentage.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1554| letterSpacing<sup>12+</sup> | number \| string             | No    | Letter spacing. If the value is negative, the text is compressed. A negative value too small may result in the text being compressed to 0 and no content being displayed. If the value is of the number type, the unit fp is used. The value cannot be a percentage.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1555| fontFeature<sup>12+</sup> | string | No | Font feature, for example, monospaced digits. If this parameter is not set, monospaced digits are used as the default value. If invalid characters are set, the default value is retrained.<br>Format: normal \| \<feature-tag-value\><br>Syntax for \<feature-tag-value\>: \<string\> \[ \<integer\> \| on \| off ]<br>There can be multiple **\<feature-tag-value\>** values, which are separated by commas (,).<br>For example, the input format for monospaced clock fonts is "ss01" on.<br>For details about the supported font features, see [Font Feature List](ts-basic-components-text.md#fontfeature12).<br>Font features are advanced typographic features, such as ligatures and monospace, for OpenType fonts. They are typically used in custom fonts and require the support of the font itself.<br>For more information about the font features, see [Low-level font feature settings control: the font-feature-settings property](https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop) and [The Complete CSS Demo for OpenType Features](https://sparanoid.com/lab/opentype-features/).<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1556
1557## PlaceholderStyle<sup>12+</sup>
1558
1559Defines the style of the placeholder text.
1560
1561**Atomic service API**: This API can be used in atomic services since API version 12.
1562
1563**System capability**: SystemCapability.ArkUI.ArkUI.Full
1564
1565| Name                          | Type                                      | Mandatory  | Description                        |
1566| ---------------------------- | ---------------------------------------- | ---- | -------------------------- |
1567| font                         | [Font](ts-types.md#font)                    | No   | Style of the placeholder text.<br>The default value follows the theme.|
1568| fontColor                    | [ResourceColor](ts-types.md#resourcecolor)  | No   | Color of the placeholder text.<br>The default value follows the theme.|
1569
1570## RichEditorImageSpanOptions
1571
1572Defines the options for adding an image span.
1573
1574**System capability**: SystemCapability.ArkUI.ArkUI.Full
1575
1576| Name                   | Type                                      | Mandatory  | Description                        |
1577| --------------------- | ---------------------------------------- | ---- | -------------------------- |
1578| offset                | number                                   | No   | Position of the image span to be added. If this parameter is omitted, the paragraph is added to the end of all content.<br>If the value specified is less than 0, the paragraph is placed at the beginning of all content. If the value is greater than the length of all content, the paragraph is placed at the end of all content.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1579| imageStyle            | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | No   | Image style. If this parameter is left empty, the default image style will be used.<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1580| gesture<sup>11+</sup> | [RichEditorGesture](#richeditorgesture11) | No   | Behavior-triggered callback. If this parameter is left empty, only the default system behavior is supported.<br>**Atomic service API**: This API can be used in atomic services since API version 12.|
1581
1582## RichEditorImageSpanStyle
1583
1584Provides the image span style information.
1585
1586**System capability**: SystemCapability.ArkUI.ArkUI.Full
1587
1588| Name                       | Type                                      | Mandatory  | Description                                      |
1589| ------------------------- | ---------------------------------------- | ---- | ---------------------------------------- |
1590| size                      | [[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)] | No   | Width and height of the image. Default value: varies by the value of **objectFit**. If the value of **objectFit** is **Cover**, the image height is the component height minus the top and bottom paddings, and the image width is the component width minus the left and right paddings.<br>**Atomic service API**: This API can be used in atomic services since API version 11.                              |
1591| verticalAlign             | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | No   | Vertical alignment mode of the image.<br>Default value: **ImageSpanAlignment.BASELINE**<br>**Atomic service API**: This API can be used in atomic services since API version 11.|
1592| objectFit                 | [ImageFit](ts-appendix-enums.md#imagefit) | No   | Scale mode of the image.<br> Default value: **ImageFit.Cover**<br>**Atomic service API**: This API can be used in atomic services since API version 11.      |
1593| layoutStyle<sup>11+</sup> | [RichEditorLayoutStyle](#richeditorlayoutstyle11) | No   | Image layout style. Default value: **{"borderRadius":"","margin":""}**<br><br>**Atomic service API**: This API can be used in atomic services since API version 12.                         |
1594
1595## RichEditorSymbolSpanOptions<sup>11+</sup>
1596
1597Defines offset position for adding the symbol span and the symbol span style.
1598
1599**Atomic service API**: This API can be used in atomic services since API version 12.
1600
1601**System capability**: SystemCapability.ArkUI.ArkUI.Full
1602
1603| Name    | Type                                      | Mandatory  | Description                        |
1604| ------ | ---------------------------------------- | ---- | -------------------------- |
1605| offset | number                                   | No   | Position of the symbol span to be added. If this parameter is omitted, the span is added to the end of all content.<br>If the value specified is less than 0, the paragraph is placed at the beginning of all content. If the value is greater than the length of all content, the paragraph is placed at the end of all content. |
1606| style  | [RichEditorSymbolSpanStyle](#richeditorsymbolspanstyle11) | No   | Style of the symbol span to be added. If this parameter is left empty, the default style will be used.    |
1607
1608## RichEditorSymbolSpanStyle<sup>11+</sup>
1609
1610Provides the symbol span style information.
1611
1612**Atomic service API**: This API can be used in atomic services since API version 12.
1613
1614**System capability**: SystemCapability.ArkUI.ArkUI.Full
1615
1616| Name | Type | Mandatory | Description                              |
1617| ------ | -------- | ---- | -------------------------------------- |
1618| fontColor | Array\<[ResourceColor](ts-types.md#resourcecolor)\> | No | Color of the symbol span.<br> Default value: varies depending on the rendering strategy. |
1619| fontSize | number \| string \| [Resource](ts-types.md#resource) | No | Size of the symbol span. The default unit is fp.<br>The default value follows the theme. |
1620| fontWeight | [FontWeight](ts-appendix-enums.md#fontweight) \| number \| string | No | Font weight of the symbol span.<br>For the number type, the value ranges from 100 to 900, at an interval of 100. A larger value indicates a heavier font weight. The default value is **400**.<br>For the string type, only strings of the number type are supported, for example, **"400"**, **"bold"**, **"bolder"**, **"lighter"**, **"regular"**, and **"medium"**, which correspond to the enumerated values in **FontWeight**.<br>Default value: **FontWeight.Normal** |
1621| renderingStrategy | [SymbolRenderingStrategy](ts-appendix-enums.md#symbolrenderingstrategy11)	| No | Rendering strategy of the symbol span.<br>Default value: **SymbolRenderingStrategy.SINGLE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_trash_circle**, **ohos_folder_badge_plus**, and **ohos_lungs** support the **MULTIPLE_COLOR** and **MULTIPLE_OPACITY** modes. |
1622| effectStrategy | [SymbolEffectStrategy](ts-appendix-enums.md#symboleffectstrategy11)	| No | Effect strategy of the symbol span.<br>Default value: **SymbolEffectStrategy.NONE**<br>**NOTE**<br>For the resources referenced in **$r('sys.symbol.ohos_*')**, only **ohos_wifi** supports the hierarchical effect. |
1623
1624## RichEditorBuilderSpanOptions<sup>11+</sup>
1625
1626Defines the options for adding an image span.
1627
1628**Atomic service API**: This API can be used in atomic services since API version 12.
1629
1630**System capability**: SystemCapability.ArkUI.ArkUI.Full
1631
1632| Name    | Type    | Mandatory  | Description                                   |
1633| ------ | ------ | ---- | ------------------------------------- |
1634| offset | number | No   | Position of the builder span to be added. If this parameter is omitted or set to an invalid value, the span is added to the end of all content. |
1635
1636## RichEditorSpan<sup>12+</sup>
1637
1638type RichEditorSpan = RichEditorTextStyleResult | RichEditorImageSpanResult
1639
1640Provides the span information of the **RichEditor** component.
1641
1642**Atomic service API**: This API can be used in atomic services since API version 11.
1643
1644**System capability**: SystemCapability.ArkUI.ArkUI.Full
1645
1646| Type  | Description      |
1647| ------ | ---------- |
1648| [RichEditorTextStyleResult](#richeditortextstyleresult) | Provides the text span style information returned by the backend. |
1649| [RichEditorImageSpanResult](#richeditorimagespanresult) | Provides the image information returned by the backend. |
1650
1651## RichEditorRange
1652
1653Provides the span range information.
1654
1655**Atomic service API**: This API can be used in atomic services since API version 11.
1656
1657**System capability**: SystemCapability.ArkUI.ArkUI.Full
1658
1659| Name   | Type    | Mandatory  | Description                    |
1660| ----- | ------ | ---- | ---------------------- |
1661| start | number | No   | Start position. If this parameter is left empty or set to a negative value, the value **0** will be used. |
1662| end   | number | No   | End position. If this parameter is left empty or set to a negative value or any value beyond the range, it indicates infinity. |
1663
1664## SelectionMenuOptions<sup>11+</sup>
1665
1666Provides the selection range information.
1667
1668**Atomic service API**: This API can be used in atomic services since API version 11.
1669
1670**System capability**: SystemCapability.ArkUI.ArkUI.Full
1671
1672| Name         | Type        | Mandatory  | Description           |
1673| ----------- | ---------- | ---- | ------------- |
1674| onAppear    | [MenuOnAppearCallback<sup>12+</sup>](#menuonappearcallback12) | No   | Callback invoked when the custom context menu on selection is displayed. |
1675| onDisappear | Callback\<void\>  | No   | Callback invoked when the custom context menu on selection is closed. |
1676
1677## PasteEvent<sup>11+</sup>
1678
1679Defines a custom paste event.
1680
1681**Atomic service API**: This API can be used in atomic services since API version 11.
1682
1683**System capability**: SystemCapability.ArkUI.ArkUI.Full
1684
1685| Name            | Type         | Mandatory  | Description                           |
1686| -------------- | ----------- | ---- | ----------------------------- |
1687| preventDefault | Callback\<void\> | No   | Prevents the default paste event. |
1688
1689## CutEvent<sup>12+</sup>
1690
1691Defines a custom cut event.
1692
1693**Atomic service API**: This API can be used in atomic services since API version 12.
1694
1695**System capability**: SystemCapability.ArkUI.ArkUI.Full
1696
1697| Name            | Type         | Mandatory  | Description                           |
1698| -------------- | ----------- | ---- | ----------------------------- |
1699| preventDefault | Callback\<void\>  | No   | Prevents the default cut event. |
1700
1701## CopyEvent<sup>12+</sup>
1702
1703Defines a custom copy event.
1704
1705**Atomic service API**: This API can be used in atomic services since API version 12.
1706
1707**System capability**: SystemCapability.ArkUI.ArkUI.Full
1708
1709| Name            | Type         | Mandatory  | Description                           |
1710| -------------- | ----------- | ---- | ----------------------------- |
1711| preventDefault | Callback\<void\>  | No   | Prevents the default copy event. |
1712
1713## RichEditorGesture<sup>11+</sup>
1714
1715Defines the behavior-triggered callbacks.
1716
1717**Atomic service API**: This API can be used in atomic services since API version 12.
1718
1719**System capability**: SystemCapability.ArkUI.ArkUI.Full
1720
1721| Name         | Type        | Mandatory  | Description           |
1722| ----------- | ---------- | ---- | ------------- |
1723| onClick    | Callback\<[ClickEvent](ts-universal-events-click.md#clickevent)\> | No   | [ClickEvent](ts-universal-events-click.md#clickevent) indicates a user click event.<br>Called when a click is complete.<br>In the case of a double-click, this API is called upon the first click.|
1724| onLongPress | Callback\<[GestureEvent](ts-gesture-settings.md#gestureevent)\>  | No   | [GestureEvent](ts-gesture-settings.md#gestureevent object description) indicates a long press event.<br>Called when a long press is complete. |
1725
1726## KeyboardOptions<sup>12+</sup>
1727
1728Whether to support keyboard avoidance.
1729
1730**System capability**: SystemCapability.ArkUI.ArkUI.Full
1731
1732| Name           | Type             | Mandatory  | Description                              |
1733| --------------- | ---------------  |---- | ------------------------------------  |
1734| supportAvoidance |  boolean      | No | Whether to support keyboard avoidance. The value **true** means to support keyboard avoidance, and **false** (default) means the opposite. |
1735
1736## SubmitCallback<sup>12+</sup>
1737
1738Represents the callback invoked when the Enter key on the soft keyboard is pressed.
1739
1740**Atomic service API**: This API can be used in atomic services since API version 12.
1741
1742**System capability**: SystemCapability.ArkUI.ArkUI.Full
1743
1744| Name    | Type                                            | Mandatory | Description                                                    |
1745| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1746| enterKey | [EnterKeyType](ts-types.md#enterkeytype) | Yes  | Type of the Enter key. For details, see **EnterKeyType**. |
1747| event    | [SubmitEvent](ts-types.md#submitevent11)         | Yes  | Submit event, which provides a method to keep the text box in editing state.        |
1748
1749## MenuOnAppearCallback<sup>12+</sup>
1750
1751Represents the callback invoked when the custom context menu on selection is displayed.
1752
1753**System capability**: SystemCapability.ArkUI.ArkUI.Full
1754
1755| Name    | Type                                            | Mandatory | Description                                                    |
1756| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1757| start | number | Yes  | Start position of the selected content. |
1758| end    | number         | Yes  | End position of the selected content.        |
1759
1760## PasteEventCallback<sup>12+</sup>
1761
1762Triggered when the paste is about to be completed.<br>
1763type PasteEventCallback = (event?: PasteEvent) => void
1764
1765**System capability**: SystemCapability.ArkUI.ArkUI.Full
1766
1767| Name    | Type                                            | Mandatory | Description                                                    |
1768| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1769| event  | [PasteEvent](#pasteevent11) | No  | Defines the custom paste event. |
1770
1771## OnDidChangeCallback<sup>12+</sup>
1772
1773type OnDidChangeCallback = (rangeBefore: TextRange, rangeAfter: TextRange) => void
1774
1775Represents the callback invoked after text changes.
1776
1777**Parameters**
1778
1779| Name | Type | Mandatory | Description |
1780| -- | -- | -- | -- |
1781| rangeBefore | [TextRange](ts-text-common.md#textrange12) | Yes | Range of the text to be changed. |
1782| rangeAfter | [TextRange](ts-text-common.md#textrange12) | Yes | Range of the text added. |
1783
1784## StyledStringChangedListener<sup>12+</sup>
1785Defines the listener for changes of the styled string text content.
1786| Name | Type | Mandatory | Description |
1787| -- | -- | -- | -- |
1788| onWillChange | Callback<[StyledStringChangeValue](#styledstringchangevalue12), boolean> | No | Callback invoked when text is about to change. |
1789| onDidChange | [OnDidChangeCallback](#ondidchangecallback12) | No | Callback invoked when text is changed. |
1790
1791## StyledStringChangeValue<sup>12+</sup>
1792Describes the text changes of the styled string.
1793
1794| Name | Type | Mandatory | Description |
1795| -- | -- | -- | -- |
1796| range | [TextRange](ts-text-common.md#textrange12) | Yes | Range of the styled string to be replaced in the original string. |
1797| replacementString | [StyledString](ts-universal-styled-string.md#styledstring) | Yes | Styled string used for replacement. |
1798
1799
1800## PreviewText<sup>12+</sup>
1801
1802Preview text.
1803
1804**System capability**: SystemCapability.ArkUI.ArkUI.Full
1805
1806| Name    | Type                                            | Mandatory | Description                                                    |
1807| -------- | ------------------------------------------------ | ---- | -------------------------------------------------------- |
1808| offset | number | Yes  | Start position of the preview text. |
1809| value    | string         | Yes  | Content of the preview text.        |
1810
1811## Example
1812
1813### Example 1
1814
1815```ts
1816// xxx.ets
1817@Entry
1818@Component
1819struct Index {
1820  controller: RichEditorController = new RichEditorController();
1821  options: RichEditorOptions = { controller: this.controller };
1822  private start: number = -1;
1823  private end: number = -1;
1824  @State message: string = "[-1, -1]"
1825  @State content: string = ""
1826
1827  build() {
1828    Column() {
1829      Column() {
1830        Text("selection range:").width("100%")
1831        Text() {
1832          Span(this.message)
1833        }.width("100%")
1834        Text("selection content:").width("100%")
1835        Text() {
1836          Span(this.content)
1837        }.width("100%")
1838      }
1839      .borderWidth(1)
1840      .borderColor(Color.Red)
1841      .width("100%")
1842      .height("20%")
1843
1844      Row() {
1845        Button ("Update Style: Bold").onClick(() => {
1846          this.controller.updateSpanStyle({
1847            start: this.start,
1848            end: this.end,
1849            textStyle:
1850            {
1851              fontWeight: FontWeight.Bolder
1852            }
1853          })
1854        })
1855        Button("Obtain Selection").onClick(() => {
1856          this.content = "";
1857          this.controller.getSpans({
1858            start: this.start,
1859            end: this.end
1860          }).forEach(item => {
1861            if(typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined'){
1862              this.content += (item as RichEditorImageSpanResult).valueResourceStr;
1863              this.content += "\n"
1864            } else {
1865              if(typeof(item as RichEditorTextSpanResult)['symbolSpanStyle'] != 'undefined') {
1866                this.content += (item as RichEditorTextSpanResult).symbolSpanStyle?.fontSize;
1867                this.content += "\n"
1868              }else {
1869                this.content += (item as RichEditorTextSpanResult).value;
1870                this.content += "\n"
1871              }
1872            }
1873          })
1874        })
1875        Button("Delete Selection").onClick(() => {
1876          this.controller.deleteSpans({
1877            start: this.start,
1878            end: this.end
1879          })
1880          this.start = -1;
1881          this.end = -1;
1882          this.message = "[" + this.start + ", " + this.end + "]"
1883        })
1884      }
1885      .borderWidth(1)
1886      .borderColor(Color.Red)
1887      .width("100%")
1888      .height("10%")
1889
1890      Column() {
1891        RichEditor(this.options)
1892          .onReady(() => {
1893            this.controller.addTextSpan("012345",
1894              {
1895                style:
1896                {
1897                  fontColor: Color.Orange,
1898                  fontSize: 30
1899                }
1900              })
1901            this.controller.addSymbolSpan($r("sys.symbol.ohos_trash"),
1902              {
1903                style:
1904                {
1905                  fontSize: 30
1906                }
1907              })
1908            this.controller.addImageSpan($r("app.media.icon"),
1909              {
1910                imageStyle:
1911                {
1912                  size: ["57px", "57px"]
1913                }
1914              })
1915            this.controller.addTextSpan("56789",
1916              {
1917                style:
1918                {
1919                  fontColor: Color.Black,
1920                  fontSize: 30
1921                }
1922              })
1923          })
1924          .onSelect((value: RichEditorSelection) => {
1925            this.start = value.selection[0];
1926            this.end = value.selection[1];
1927            this.message = "[" + this.start + ", " + this.end + "]"
1928          })
1929          .aboutToIMEInput((value: RichEditorInsertValue) => {
1930            console.log("---------------------- aboutToIMEInput ----------------------")
1931            console.log("insertOffset:" + value.insertOffset)
1932            console.log("insertValue:" + value.insertValue)
1933            return true;
1934          })
1935          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
1936            console.log("---------------------- onIMEInputComplete ---------------------")
1937            console.log("spanIndex:" + value.spanPosition.spanIndex)
1938            console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]")
1939            console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]")
1940            console.log("value:" + value.value)
1941          })
1942          .aboutToDelete((value: RichEditorDeleteValue) => {
1943            console.log("---------------------- aboutToDelete --------------------------")
1944            console.log("offset:" + value.offset)
1945            console.log("direction:" + value.direction)
1946            console.log("length:" + value.length)
1947            value.richEditorDeleteSpans.forEach(item => {
1948              console.log("---------------------- item --------------------------")
1949              console.log("spanIndex:" + item.spanPosition.spanIndex)
1950              console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]")
1951              console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]")
1952              if (typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
1953                console.log("image:" + (item as RichEditorImageSpanResult).valueResourceStr)
1954              } else {
1955                console.log("text:" + (item as RichEditorTextSpanResult).value)
1956              }
1957            })
1958            return true;
1959          })
1960          .onDeleteComplete(() => {
1961            console.log("---------------------- onDeleteComplete ------------------------")
1962          })
1963          .placeholder("input...", {
1964            fontColor: Color.Gray,
1965            font: {
1966              size: 16,
1967              weight: FontWeight.Normal,
1968              family: "HarmonyOS Sans",
1969              style: FontStyle.Normal
1970            }
1971          })
1972          .borderWidth(1)
1973          .borderColor(Color.Green)
1974          .width("100%")
1975          .height("30%")
1976      }
1977      .borderWidth(1)
1978      .borderColor(Color.Red)
1979      .width("100%")
1980      .height("70%")
1981    }
1982  }
1983}
1984```
1985![richeditor](figures/richeditor.gif)
1986
1987### Example 2
1988
1989```ts
1990// xxx.ets
1991@Entry
1992@Component
1993struct RichEditorExample {
1994  controller: RichEditorController = new RichEditorController()
1995
1996  // Create a custom keyboard component.
1997  @Builder CustomKeyboardBuilder() {
1998    Column() {
1999      Grid() {
2000        ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, '*', 0, '#'], (item: number | string) => {
2001          GridItem() {
2002            Button(item + "")
2003              .width(110).onClick(() => {
2004              this.controller.addTextSpan(item + '', {
2005                offset: this.controller.getCaretOffset(),
2006                style:
2007                {
2008                  fontColor: Color.Orange,
2009                  fontSize: 30
2010                }
2011              })
2012              this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length)
2013            })
2014          }
2015        })
2016      }.maxCount(3).columnsGap(10).rowsGap(10).padding(5)
2017    }.backgroundColor(Color.Gray)
2018  }
2019
2020  build() {
2021    Column() {
2022      RichEditor({ controller: this.controller })
2023        // Bind the custom keyboard.
2024        .customKeyboard(this.CustomKeyboardBuilder()).margin(10).border({ width: 1 })
2025        .height(200)
2026        .borderWidth(1)
2027        .borderColor(Color.Red)
2028        .width("100%")
2029    }
2030  }
2031}
2032```
2033
2034![customKeyboard](figures/richEditorCustomKeyboard.gif)
2035
2036### Example 3
2037
2038```ts
2039// xxx.ets
2040import { BusinessError, pasteboard } from '@kit.BasicServicesKit';
2041
2042export interface SelectionMenuTheme {
2043  imageSize: number;
2044  buttonSize: number;
2045  menuSpacing: number;
2046  editorOptionMargin: number;
2047  expandedOptionPadding: number;
2048  defaultMenuWidth: number;
2049  imageFillColor: Resource;
2050  backGroundColor: Resource;
2051  iconBorderRadius: Resource;
2052  containerBorderRadius: Resource;
2053  cutIcon: Resource;
2054  copyIcon: Resource;
2055  pasteIcon: Resource;
2056  selectAllIcon: Resource;
2057  shareIcon: Resource;
2058  translateIcon: Resource;
2059  searchIcon: Resource;
2060  arrowDownIcon: Resource;
2061  iconPanelShadowStyle: ShadowStyle;
2062  iconFocusBorderColor: Resource;
2063}
2064
2065export const defaultTheme: SelectionMenuTheme = {
2066  imageSize: 24,
2067  buttonSize: 48,
2068  menuSpacing: 8,
2069  editorOptionMargin: 1,
2070  expandedOptionPadding: 3,
2071  defaultMenuWidth: 256,
2072  imageFillColor: $r('sys.color.ohos_id_color_primary'),
2073  backGroundColor: $r('sys.color.ohos_id_color_dialog_bg'),
2074  iconBorderRadius: $r('sys.float.ohos_id_corner_radius_default_m'),
2075  containerBorderRadius: $r('sys.float.ohos_id_corner_radius_card'),
2076  cutIcon: $r("sys.media.ohos_ic_public_cut"),
2077  copyIcon: $r("sys.media.ohos_ic_public_copy"),
2078  pasteIcon: $r("sys.media.ohos_ic_public_paste"),
2079  selectAllIcon: $r("sys.media.ohos_ic_public_select_all"),
2080  shareIcon: $r("sys.media.ohos_ic_public_share"),
2081  translateIcon: $r("sys.media.ohos_ic_public_translate_c2e"),
2082  searchIcon: $r("sys.media.ohos_ic_public_search_filled"),
2083  arrowDownIcon: $r("sys.media.ohos_ic_public_arrow_down"),
2084  iconPanelShadowStyle: ShadowStyle.OUTER_DEFAULT_MD,
2085  iconFocusBorderColor: $r('sys.color.ohos_id_color_focused_outline'),
2086}
2087
2088@Entry
2089@Component
2090struct SelectionMenu {
2091  @State message: string = 'Hello World'
2092  @State textSize: number = 40
2093  @State sliderShow: boolean = false
2094  @State start: number = -1
2095  @State end: number = -1
2096  @State colorTransparent: Color = Color.Transparent
2097  controller: RichEditorController = new RichEditorController();
2098  options: RichEditorOptions = { controller: this.controller }
2099  private iconArr: Array<Resource> =
2100    [$r('app.media.icon'), $r("app.media.icon"), $r('app.media.icon'),
2101    $r("app.media.icon"), $r('app.media.icon')]
2102  @State iconBgColor: ResourceColor[] = new Array(this.iconArr.length).fill(this.colorTransparent)
2103  @State pasteEnable: boolean = false
2104  @State visibilityValue: Visibility = Visibility.Visible
2105  @State textStyle: RichEditorTextStyle = {}
2106  private fontWeightTable: string[] = ["100", "200", "300", "400", "500", "600", "700", "800", "900", "bold", "normal", "bolder", "lighter", "medium", "regular"]
2107  private theme: SelectionMenuTheme = defaultTheme;
2108
2109  aboutToAppear() {
2110    if (this.controller) {
2111      let richEditorSelection = this.controller.getSelection()
2112      if (richEditorSelection) {
2113        let start = richEditorSelection.selection[0]
2114        let end = richEditorSelection.selection[1]
2115        if (start === 0 && this.controller.getSpans({ start: end + 1, end: end + 1 }).length === 0) {
2116          this.visibilityValue = Visibility.None
2117        } else {
2118          this.visibilityValue = Visibility.Visible
2119        }
2120      }
2121    }
2122    let sysBoard = pasteboard.getSystemPasteboard()
2123    if (sysBoard && sysBoard.hasDataSync()) {
2124      this.pasteEnable = true
2125    } else {
2126      this.pasteEnable = false
2127    }
2128  }
2129
2130  build() {
2131    Column() {
2132      Column() {
2133        RichEditor(this.options)
2134          .onReady(() => {
2135            this.controller.addTextSpan(this.message, { style: { fontColor: Color.Orange, fontSize: 30 } })
2136          })
2137          .onSelect((value: RichEditorSelection) => {
2138            if (value.selection[0] == -1 && value.selection[1] == -1) {
2139              return
2140            }
2141            this.start = value.selection[0]
2142            this.end = value.selection[1]
2143          })
2144          .bindSelectionMenu(RichEditorSpanType.TEXT, this.panel, ResponseType.LongPress, { onDisappear: () => {
2145            this.sliderShow = false
2146          }})
2147          .bindSelectionMenu(RichEditorSpanType.TEXT, this.panel, ResponseType.RightClick, { onDisappear: () => {
2148            this.sliderShow = false
2149          }})
2150          .borderWidth(1)
2151          .borderColor(Color.Red)
2152          .width(200)
2153          .height(200)
2154      }.width('100%').backgroundColor(Color.White)
2155    }.height('100%')
2156  }
2157
2158  PushDataToPasteboard(richEditorSelection: RichEditorSelection) {
2159    let sysBoard = pasteboard.getSystemPasteboard()
2160    let pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, '')
2161    if (richEditorSelection.spans && richEditorSelection.spans.length > 0) {
2162      let count = richEditorSelection.spans.length
2163      for (let i = count - 1; i >= 0; i--) {
2164        let item = richEditorSelection.spans[i]
2165        if ((item as RichEditorTextSpanResult)?.textStyle) {
2166          let span = item as RichEditorTextSpanResult
2167          let style = span.textStyle
2168          let data = pasteboard.createRecord(pasteboard.MIMETYPE_TEXT_PLAIN, span.value.substring(span.offsetInSpan[0], span.offsetInSpan[1]))
2169          let prop = pasteData.getProperty()
2170          let temp: Record<string, Object> = {
2171            'color': style.fontColor,
2172            'size': style.fontSize,
2173            'style': style.fontStyle,
2174            'weight': this.fontWeightTable[style.fontWeight],
2175            'fontFamily': style.fontFamily,
2176            'decorationType': style.decoration.type,
2177            'decorationColor': style.decoration.color
2178          }
2179          prop.additions[i] = temp;
2180          pasteData.addRecord(data)
2181          pasteData.setProperty(prop)
2182        }
2183      }
2184    }
2185    sysBoard.clearData()
2186    sysBoard.setData(pasteData).then(() => {
2187      console.info('SelectionMenu copy option, Succeeded in setting PasteData.');
2188      this.pasteEnable = true;
2189    }).catch((err: BusinessError) => {
2190      console.error('SelectionMenu copy option, Failed to set PasteData. Cause:' + err.message);
2191    })
2192  }
2193
2194  PopDataFromPasteboard(richEditorSelection: RichEditorSelection) {
2195    let start = richEditorSelection.selection[0]
2196    let end = richEditorSelection.selection[1]
2197    if (start == end && this.controller) {
2198      start = this.controller.getCaretOffset()
2199      end = this.controller.getCaretOffset()
2200    }
2201    let moveOffset = 0
2202    let sysBoard = pasteboard.getSystemPasteboard()
2203    sysBoard.getData((err, data) => {
2204      if (err) {
2205        return
2206      }
2207      let count = data.getRecordCount()
2208      for (let i = 0; i < count; i++) {
2209        const element = data.getRecord(i);
2210        let tex: RichEditorTextStyle = {
2211          fontSize: 16,
2212          fontColor: Color.Black,
2213          fontWeight: FontWeight.Normal,
2214          fontFamily: "HarmonyOS Sans",
2215          fontStyle: FontStyle.Normal,
2216          decoration: { type: TextDecorationType.None, color: "#FF000000", style: TextDecorationStyle.SOLID }
2217        }
2218        if (data.getProperty() && data.getProperty().additions[i]) {
2219          const tmp = data.getProperty().additions[i] as Record<string, Object | undefined>;
2220          if (tmp.color) {
2221            tex.fontColor = tmp.color as ResourceColor;
2222          }
2223          if (tmp.size) {
2224            tex.fontSize = tmp.size as Length | number;
2225          }
2226          if (tmp.style) {
2227            tex.fontStyle = tmp.style as FontStyle;
2228          }
2229          if (tmp.weight) {
2230            tex.fontWeight = tmp.weight as number | FontWeight | string;
2231          }
2232          if (tmp.fontFamily) {
2233            tex.fontFamily = tmp.fontFamily as ResourceStr;
2234          }
2235          if (tmp.decorationType && tex.decoration) {
2236            tex.decoration.type = tmp.decorationType as TextDecorationType;
2237          }
2238          if (tmp.decorationColor && tex.decoration) {
2239            tex.decoration.color = tmp.decorationColor as ResourceColor;
2240          }
2241          if (tex.decoration) {
2242            tex.decoration = { type: tex.decoration.type, color: tex.decoration.color }
2243          }
2244        }
2245        if (element && element.plainText && element.mimeType === pasteboard.MIMETYPE_TEXT_PLAIN && this.controller) {
2246          this.controller.addTextSpan(element.plainText,
2247            {
2248              style: tex,
2249              offset: start + moveOffset
2250            }
2251          )
2252          moveOffset += element.plainText.length
2253        }
2254      }
2255      if (this.controller) {
2256        this.controller.setCaretOffset(start + moveOffset)
2257        this.controller.closeSelectionMenu()
2258      }
2259      if (start != end && this.controller) {
2260        this.controller.deleteSpans({ start: start + moveOffset, end: end + moveOffset })
2261      }
2262    })
2263  }
2264
2265  @Builder
2266  panel() {
2267    Column() {
2268      this.iconPanel()
2269      if (!this.sliderShow) {
2270        this.SystemMenu()
2271      } else {
2272        this.sliderPanel()
2273      }
2274    }.width(256)
2275  }
2276
2277  @Builder iconPanel() {
2278    Column() {
2279      Row({ space: 2 }) {
2280        ForEach(this.iconArr, (item:Resource, index ?: number) => {
2281          Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
2282            Image(item).fillColor(this.theme.imageFillColor).width(24).height(24).focusable(true).draggable(false)
2283          }
2284          .borderRadius(this.theme.iconBorderRadius)
2285          .width(this.theme.buttonSize)
2286          .height(this.theme.buttonSize)
2287          .onClick(() => {
2288            if (index as number == 0) {
2289              this.sliderShow = false
2290              if (this.controller) {
2291                let selection = this.controller.getSelection();
2292                let spans = selection.spans
2293                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2294                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2295                    let span = item as RichEditorTextSpanResult
2296                    this.textStyle = span.textStyle
2297                    let start = span.offsetInSpan[0]
2298                    let end = span.offsetInSpan[1]
2299                    let offset = span.spanPosition.spanRange[0]
2300                    if (this.textStyle.fontWeight != 11) {
2301                      this.textStyle.fontWeight = FontWeight.Bolder
2302                    } else {
2303                      this.textStyle.fontWeight = FontWeight.Normal
2304                    }
2305                    this.controller.updateSpanStyle({
2306                      start: offset + start,
2307                      end: offset + end,
2308                      textStyle: this.textStyle
2309                    })
2310                  }
2311                })
2312              }
2313            } else if (index as number == 1) {
2314              this.sliderShow = false
2315              if (this.controller) {
2316                let selection = this.controller.getSelection();
2317                let spans = selection.spans
2318                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2319                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2320                    let span = item as RichEditorTextSpanResult
2321                    this.textStyle = span.textStyle
2322                    let start = span.offsetInSpan[0]
2323                    let end = span.offsetInSpan[1]
2324                    let offset = span.spanPosition.spanRange[0]
2325                    if (this.textStyle.fontStyle == FontStyle.Italic) {
2326                      this.textStyle.fontStyle = FontStyle.Normal
2327                    } else {
2328                      this.textStyle.fontStyle = FontStyle.Italic
2329                    }
2330                    this.controller.updateSpanStyle({
2331                      start: offset + start,
2332                      end: offset + end,
2333                      textStyle: this.textStyle
2334                    })
2335                  }
2336                })
2337              }
2338            } else if (index as number == 2) {
2339              this.sliderShow = false
2340              if (this.controller) {
2341                let selection = this.controller.getSelection();
2342                let spans = selection.spans
2343                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2344                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2345                    let span = item as RichEditorTextSpanResult
2346                    this.textStyle = span.textStyle
2347                    let start = span.offsetInSpan[0]
2348                    let end = span.offsetInSpan[1]
2349                    let offset = span.spanPosition.spanRange[0]
2350                    if (this.textStyle.decoration) {
2351                      if (this.textStyle.decoration.type == TextDecorationType.Underline) {
2352                        this.textStyle.decoration.type = TextDecorationType.None
2353                      } else {
2354                        this.textStyle.decoration.type = TextDecorationType.Underline
2355                      }
2356                    } else {
2357                      this.textStyle.decoration = { type: TextDecorationType.Underline, color: Color.Black, style: TextDecorationStyle.SOLID }
2358                    }
2359                    this.controller.updateSpanStyle({
2360                      start: offset + start,
2361                      end: offset + end,
2362                      textStyle: this.textStyle
2363                    })
2364                  }
2365                })
2366              }
2367            } else if (index as number == 3) {
2368              this.sliderShow = !this.sliderShow
2369            } else if (index as number == 4) {
2370              this.sliderShow = false
2371              if (this.controller) {
2372                let selection = this.controller.getSelection();
2373                let spans = selection.spans
2374                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2375                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2376                    let span = item as RichEditorTextSpanResult
2377                    this.textStyle = span.textStyle
2378                    let start = span.offsetInSpan[0]
2379                    let end = span.offsetInSpan[1]
2380                    let offset = span.spanPosition.spanRange[0]
2381                    if (this.textStyle.fontColor == Color.Orange || this.textStyle.fontColor == '#FFFFA500') {
2382                      this.textStyle.fontColor = Color.Black
2383                    } else {
2384                      this.textStyle.fontColor = Color.Orange
2385                    }
2386                    this.controller.updateSpanStyle({
2387                      start: offset + start,
2388                      end: offset + end,
2389                      textStyle: this.textStyle
2390                    })
2391                  }
2392                })
2393              }
2394            }
2395          })
2396          .onTouch((event?: TouchEvent | undefined) => {
2397            if(event != undefined){
2398              if (event.type === TouchType.Down) {
2399                this.iconBgColor[index as number] = $r('sys.color.ohos_id_color_click_effect')
2400              }
2401              if (event.type === TouchType.Up) {
2402                this.iconBgColor[index as number] = this.colorTransparent
2403              }
2404            }
2405          })
2406          .onHover((isHover?: boolean, event?: HoverEvent) => {
2407            this.iconBgColor.forEach((icon:ResourceColor, index1) => {
2408              this.iconBgColor[index1] = this.colorTransparent
2409            })
2410            if(isHover != undefined) {
2411              this.iconBgColor[index as number] = $r('sys.color.ohos_id_color_hover')
2412            }
2413          })
2414          .backgroundColor(this.iconBgColor[index as number])
2415        })
2416      }
2417    }
2418    .clip(true)
2419    .width(this.theme.defaultMenuWidth)
2420    .padding(this.theme.expandedOptionPadding)
2421    .borderRadius(this.theme.containerBorderRadius)
2422    .margin({ bottom: this.theme.menuSpacing })
2423    .backgroundColor(this.theme.backGroundColor)
2424    .shadow(this.theme.iconPanelShadowStyle)
2425  }
2426
2427  @Builder
2428  SystemMenu() {
2429    Column() {
2430      Menu() {
2431        if (this.controller) {
2432          MenuItemGroup() {
2433            MenuItem({ startIcon: this.theme.cutIcon, content: "Cut", labelInfo: "Ctrl+X" })
2434              .onClick(() => {
2435                if (!this.controller) {
2436                  return
2437                }
2438                let richEditorSelection = this.controller.getSelection()
2439                this.PushDataToPasteboard(richEditorSelection);
2440                this.controller.deleteSpans({
2441                  start: richEditorSelection.selection[0],
2442                  end: richEditorSelection.selection[1]
2443                })
2444              })
2445            MenuItem({ startIcon: this.theme.copyIcon, content: "Copy", labelInfo: "Ctrl+C" })
2446              .onClick(() => {
2447                if (!this.controller) {
2448                  return
2449                }
2450                let richEditorSelection = this.controller.getSelection()
2451                this.PushDataToPasteboard(richEditorSelection);
2452                this.controller.closeSelectionMenu()
2453              })
2454            MenuItem({ startIcon: this.theme.pasteIcon, content: "Paste", labelInfo: "Ctrl+V" })
2455              .enabled(this.pasteEnable)
2456              .onClick(() => {
2457                if (!this.controller) {
2458                  return
2459                }
2460                let richEditorSelection = this.controller.getSelection()
2461                this.PopDataFromPasteboard(richEditorSelection)
2462              })
2463            MenuItem({ startIcon: this.theme.selectAllIcon, content: "Select all", labelInfo: "Ctrl+A" })
2464              .visibility(this.visibilityValue)
2465              .onClick(() => {
2466                if (!this.controller) {
2467                  return
2468                }
2469                this.controller.setSelection(-1, -1)
2470                this.visibilityValue = Visibility.None
2471              })
2472            MenuItem({ startIcon: this.theme.shareIcon, content: "Share", labelInfo: "" })
2473              .enabled(false)
2474            MenuItem({ startIcon: this.theme.translateIcon, content: "Translate", labelInfo: "" })
2475              .enabled(false)
2476            MenuItem({ startIcon: this.theme.searchIcon, content: "Search", labelInfo: "" })
2477              .enabled(false)
2478          }
2479        }
2480      }
2481      .onVisibleAreaChange([0.0, 1.0], () => {
2482        if (!this.controller) {
2483          return
2484        }
2485        let richEditorSelection = this.controller.getSelection()
2486        let start = richEditorSelection.selection[0]
2487        let end = richEditorSelection.selection[1]
2488        if (start === 0 && this.controller.getSpans({ start: end + 1, end: end + 1 }).length === 0) {
2489          this.visibilityValue = Visibility.None
2490        } else {
2491          this.visibilityValue = Visibility.Visible
2492        }
2493      })
2494      .radius(this.theme.containerBorderRadius)
2495      .clip(true)
2496      .backgroundColor(Color.White)
2497      .width(this.theme.defaultMenuWidth)
2498    }
2499    .width(this.theme.defaultMenuWidth)
2500  }
2501
2502  @Builder sliderPanel() {
2503    Column() {
2504      Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
2505        Text('A').fontSize(15)
2506        Slider({ value: this.textSize, step: 10, style: SliderStyle.InSet })
2507          .width(210)
2508          .onChange((value: number, mode: SliderChangeMode) => {
2509            if (this.controller) {
2510              let selection = this.controller.getSelection();
2511              if (mode == SliderChangeMode.End) {
2512                if (this.textSize == undefined) {
2513                  this.textSize = 0
2514                }
2515                let spans = selection.spans
2516                spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => {
2517                  if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') {
2518                    this.textSize = Math.max(this.textSize, (item as RichEditorTextSpanResult).textStyle.fontSize)
2519                  }
2520                })
2521              }
2522              if (mode == SliderChangeMode.Moving || mode == SliderChangeMode.Click) {
2523                this.start = selection.selection[0]
2524                this.end = selection.selection[1]
2525                this.textSize = value
2526                this.controller.updateSpanStyle({
2527                  start: this.start,
2528                  end: this.end,
2529                  textStyle: { fontSize: this.textSize }
2530                })
2531              }
2532            }
2533          })
2534        Text('A').fontSize(20).fontWeight(FontWeight.Medium)
2535      }.borderRadius(this.theme.containerBorderRadius)
2536    }
2537    .shadow(ShadowStyle.OUTER_DEFAULT_MD)
2538    .backgroundColor(Color.White)
2539    .borderRadius(this.theme.containerBorderRadius)
2540    .padding(15)
2541    .height(48)
2542  }
2543}
2544```
2545> **NOTE**
2546>
2547> Icons in bold and italics are not preset in the system. The sample code uses the default icons. You need to replace the icons in **iconArr** with the desired icons.
2548
2549![selectionMenu](figures/richEditorSelectionMenu.png)
2550
2551### Example 4
2552
2553```ts
2554// xxx.ets
2555@Entry
2556@Component
2557struct Index {
2558  controller: RichEditorController = new RichEditorController();
2559  options: RichEditorOptions = { controller: this.controller };
2560  private start: number = -1;
2561  private end: number = -1;
2562  @State message: string = "[-1, -1]"
2563  @State content: string = ""
2564  @State paddingVal: number = 5
2565  @State borderRad: number = 4
2566
2567  build() {
2568    Column() {
2569      Column() {
2570        Text("selection range:").width("100%")
2571        Text() {
2572          Span(this.message)
2573        }.width("100%")
2574        Text("selection content:").width("100%")
2575        Text() {
2576          Span(this.content)
2577        }.width("100%")
2578      }
2579      .borderWidth(1)
2580      .borderColor(Color.Red)
2581      .width("100%")
2582      .height("20%")
2583
2584      Row() {
2585        Button("updateSpanStyle1")
2586          .fontSize(12)
2587          .onClick(() => {
2588            this.controller.updateSpanStyle({
2589              start: this.start,
2590              textStyle:
2591              {
2592                fontWeight: FontWeight.Bolder
2593              },
2594              imageStyle: {
2595                size: ["80px", "80px"],
2596                layoutStyle: {
2597                  borderRadius: undefined,
2598                  margin: undefined
2599                }
2600              }
2601            })
2602          })
2603
2604        Button("updateSpanStyle2")
2605          .fontSize(12)
2606          .onClick(() => {
2607            this.controller.updateSpanStyle({
2608              start: this.start,
2609              textStyle:
2610              {
2611                fontWeight: FontWeight.Bolder
2612              },
2613              imageStyle: {
2614                size: ["70px", "70px"],
2615                layoutStyle: {
2616                  borderRadius: { topLeft: '100px', topRight: '20px', bottomLeft: '100px', bottomRight: '20px' },
2617                  margin: { left: '30px', top: '20px', right: '20px', bottom: '20px' }
2618                }
2619              }
2620            })
2621          })
2622
2623        Button("updateSpanStyle3")
2624          .fontSize(12)
2625          .onClick(() => {
2626            this.controller.updateSpanStyle({
2627              start: this.start,
2628              textStyle:
2629              {
2630                fontWeight: FontWeight.Bolder
2631              },
2632              imageStyle: {
2633                size: ["60px", "60px"],
2634                layoutStyle: {
2635                  borderRadius: '-10px',
2636                  margin: '-10px'
2637                }
2638              }
2639            })
2640          })
2641      }
2642      .borderWidth(1)
2643      .borderColor(Color.Red)
2644      .width("100%")
2645      .height("10%")
2646
2647      Row() {
2648        Button('addImageSpan1')
2649          .fontSize(12)
2650          .onClick(() => {
2651            this.controller.addImageSpan($r('app.media.app_icon'), {
2652              imageStyle: {
2653                size: ["80px", "80px"],
2654                layoutStyle: {
2655                  borderRadius: '50px',
2656                  margin: '40px'
2657                }
2658              }
2659            })
2660          })
2661
2662        Button('addImageSpan2')
2663          .fontSize(12)
2664          .onClick(() => {
2665            this.controller.addImageSpan($r('app.media.app_icon'), {
2666              imageStyle: {
2667                size: ["100px", "100px"],
2668                verticalAlign: ImageSpanAlignment.BOTTOM,
2669                layoutStyle: {
2670                  borderRadius: undefined,
2671                  margin: undefined
2672                }
2673              }
2674            })
2675          })
2676
2677        Button('addImageSpan3')
2678          .fontSize(12)
2679          .onClick(() => {
2680            this.controller.addImageSpan($r('app.media.app_icon'), {
2681              imageStyle: {
2682                size: ["60px", "60px"],
2683                verticalAlign: ImageSpanAlignment.BOTTOM,
2684                layoutStyle: {
2685                  borderRadius: { topLeft: '10px', topRight: '20px', bottomLeft: '30px', bottomRight: '40px' },
2686                  margin: { left: '10px', top: '20px', right: '30px', bottom: '40px' }
2687                }
2688              }
2689            })
2690          })
2691      }
2692      .borderWidth(1)
2693      .borderColor(Color.Red)
2694      .width("100%")
2695      .height("10%")
2696
2697      Column() {
2698        RichEditor(this.options)
2699          .onReady(() => {
2700            this.controller.addTextSpan("0123456789",
2701              {
2702                style:
2703                {
2704                  fontColor: Color.Orange,
2705                  fontSize: 30
2706                }
2707              })
2708
2709            this.controller.addImageSpan($r("app.media.app_icon"),
2710              {
2711                imageStyle:
2712                {
2713                  size: ["60px", "60px"],
2714                  verticalAlign: ImageSpanAlignment.BOTTOM,
2715                  layoutStyle: {
2716                    borderRadius: { topLeft: '10px', topRight: '20px', bottomLeft: '30px', bottomRight: '40px' },
2717                    margin: { left: '10px', top: '20px', right: '30px', bottom: '40px' }
2718                  }
2719                }
2720              })
2721
2722            this.controller.addTextSpan("0123456789",
2723              {
2724                style:
2725                {
2726                  fontColor: Color.Black,
2727                  fontSize: 30
2728                }
2729              })
2730          })
2731          .onSelect((value: RichEditorSelection) => {
2732            this.start = value.selection[0];
2733            this.end = value.selection[1];
2734            this.message = "[" + this.start + ", " + this.end + "]"
2735          })
2736          .aboutToIMEInput((value: RichEditorInsertValue) => {
2737            console.log("---------------------- aboutToIMEInput ----------------------")
2738            console.log("insertOffset:" + value.insertOffset)
2739            console.log("insertValue:" + value.insertValue)
2740            return true;
2741          })
2742          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
2743            console.log("---------------------- onIMEInputComplete ---------------------")
2744            console.log("spanIndex:" + value.spanPosition.spanIndex)
2745            console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]")
2746            console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]")
2747            console.log("value:" + value.value)
2748          })
2749          .aboutToDelete((value: RichEditorDeleteValue) => {
2750            console.log("---------------------- aboutToDelete --------------------------")
2751            console.log("offset:" + value.offset)
2752            console.log("direction:" + value.direction)
2753            console.log("length:" + value.length)
2754            value.richEditorDeleteSpans.forEach(item => {
2755              console.log("---------------------- item --------------------------")
2756              console.log("spanIndex:" + item.spanPosition.spanIndex)
2757              console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]")
2758              console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]")
2759              if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
2760                console.log("image:" + (item as RichEditorImageSpanResult).valueResourceStr)
2761              } else {
2762                console.log("text:" + (item as RichEditorTextSpanResult).value)
2763              }
2764            })
2765            return true;
2766          })
2767          .onDeleteComplete(() => {
2768            console.log("---------------------- onDeleteComplete ------------------------")
2769          })
2770          .borderWidth(1)
2771          .borderColor(Color.Green)
2772          .width("100%")
2773          .height('80.00%')
2774      }
2775      .borderWidth(1)
2776      .borderColor(Color.Red)
2777      .width("100%")
2778      .height("70%")
2779    }
2780  }
2781}
2782```
2783![ImageSpanStyle](figures/richEditorImageSpanStyle.gif)
2784
2785### Example 5
2786
2787```ts
2788// xxx.ets
2789@Entry
2790@Component
2791struct Index {
2792  controller: RichEditorController = new RichEditorController()
2793  options: RichEditorOptions = { controller: this.controller };
2794  @State textFlag: string = "TextFlag";
2795
2796  build() {
2797    Column() {
2798      Column() {
2799        Text(this.textFlag)
2800          .copyOption(CopyOptions.InApp)
2801          .fontSize(50)
2802      }
2803      Divider()
2804      Column() {
2805        RichEditor(this.options)
2806          .onReady(() => {
2807            this.controller.addTextSpan('Area1\n', {
2808              style:
2809              {
2810                fontColor: Color.Orange,
2811                fontSize: 50
2812              },
2813              gesture:
2814              {
2815                onClick: () => {
2816                  this.textFlag = "Area1 is onClick."
2817                },
2818                onLongPress: () => {
2819                  this.textFlag = "Area1 is onLongPress."
2820                }
2821              }
2822            })
2823
2824            this.controller.addTextSpan('Area2\n', {
2825              style:
2826              {
2827                fontColor: Color.Blue,
2828                fontSize: 50
2829              },
2830              gesture:
2831              {
2832                onClick: () => {
2833                  this.textFlag = "Area2 is onClick."
2834                },
2835                onLongPress: () => {
2836                  this.textFlag = "Area2 is onLongPress."
2837                }
2838              }
2839            })
2840
2841            this.controller.addImageSpan($r("app.media.icon"),
2842              {
2843                imageStyle:
2844                {
2845                  size: ["100px", "100px"],
2846                  layoutStyle: {
2847                    margin: 5,
2848                    borderRadius: 15
2849                  }
2850                },
2851                gesture:
2852                {
2853                  onClick: () => {
2854                    this.textFlag = "ImageSpan is onClick."
2855                  },
2856                  onLongPress: () => {
2857                    this.textFlag = "ImageSpan is onLongPress."
2858                  }
2859                }
2860              })
2861          })
2862      }
2863      .borderWidth(1)
2864      .borderColor(Color.Red)
2865      .width("100%")
2866      .height("70%")
2867    }
2868  }
2869}
2870```
2871![OnClickAndLongPress](figures/richEditorOnClickAndLongPress.gif)
2872
2873### Example 6
2874
2875```ts
2876// xxx.ets
2877@Entry
2878@Component
2879struct Index {
2880  controller: RichEditorController = new RichEditorController();
2881  private spanParagraphs: RichEditorParagraphResult[] = [];
2882
2883  build() {
2884    Column() {
2885      RichEditor({ controller: this.controller })
2886        .onReady(() => {
2887          this.controller.addTextSpan("0123456789\n", {
2888            style: {
2889              fontColor: Color.Pink,
2890              fontSize: "32",
2891            },
2892            paragraphStyle: {
2893              textAlign: TextAlign.Start,
2894              leadingMargin: 16
2895            }
2896          })
2897          this.controller.addTextSpan("0123456789")
2898        })
2899        .width("80%")
2900        .height("30%")
2901        .border({ width: 1, radius: 5 })
2902        .draggable(false)
2903
2904      Column({ space: 5 }) {
2905        Button ("Align left").onClick () => {
2906          this.controller.updateParagraphStyle({ start: -1, end: -1,
2907            style: {
2908              textAlign: TextAlign.Start,
2909            }
2910          })
2911        })
2912
2913        Button ("Align right").onClick(() => {
2914          this.controller.updateParagraphStyle({ start: -1, end: -1,
2915            style: {
2916              textAlign: TextAlign.End,
2917            }
2918          })
2919        })
2920
2921        Button ("Center").onClick ((). => {
2922          this.controller.updateParagraphStyle({ start: -1, end: -1,
2923            style: {
2924              textAlign: TextAlign.Center,
2925            }
2926          })
2927        })
2928        Divider()
2929        Button("getParagraphs").onClick(() => {
2930          this.spanParagraphs = this.controller.getParagraphs({ start: -1, end: -1 })
2931          console.log("RichEditor getParagraphs:" + JSON.stringify(this.spanParagraphs))
2932        })
2933
2934        Button("UpdateSpanStyle1").onClick(() => {
2935          this.controller.updateSpanStyle({ start: -1, end: -1,
2936            textStyle: {
2937              fontColor: Color.Brown,
2938              fontSize: 20
2939            }
2940          })
2941        })
2942
2943        Button("UpdateSpanStyle2").onClick(() => {
2944          this.controller.updateSpanStyle({ start: -1, end: -1,
2945            textStyle: {
2946              fontColor: Color.Green,
2947              fontSize: 30
2948            }
2949          })
2950        })
2951      }
2952    }
2953  }
2954}
2955```
2956![TextAlignAndGetParagraphInfo](figures/richEditorTextAlignAndGetParagraphInfo.gif)
2957
2958### Example 7
2959
2960```ts
2961// xxx.ets
2962import { font } from '@kit.ArkUI'
2963
2964const canvasWidth = 1000
2965const canvasHeight = 100
2966const Indentation = 40
2967class LeadingMarginCreator {
2968  private settings: RenderingContextSettings = new RenderingContextSettings(true)
2969  private offscreenCanvas: OffscreenCanvas = new OffscreenCanvas(canvasWidth, canvasHeight)
2970  private offContext: OffscreenCanvasRenderingContext2D = this.offscreenCanvas.getContext("2d", this.settings)
2971  public static instance: LeadingMarginCreator = new LeadingMarginCreator()
2972
2973  // Obtain the font size level, which ranges from 0 to 4.
2974  public getFontSizeLevel(fontSize: number) {
2975    const fontScaled: number = Number(fontSize) / 16
2976
2977    enum FontSizeScaleThreshold {
2978      SMALL = 0.9,
2979      NORMAL = 1.1,
2980      LEVEL_1_LARGE = 1.2,
2981      LEVEL_2_LARGE = 1.4,
2982      LEVEL_3_LARGE = 1.5
2983    }
2984
2985    let fontSizeLevel: number = 1
2986
2987    if (fontScaled < FontSizeScaleThreshold.SMALL) {
2988      fontSizeLevel = 0
2989    } else if (fontScaled < FontSizeScaleThreshold.NORMAL) {
2990      fontSizeLevel = 1
2991    } else if (fontScaled < FontSizeScaleThreshold.LEVEL_1_LARGE) {
2992      fontSizeLevel = 2
2993    } else if (fontScaled < FontSizeScaleThreshold.LEVEL_2_LARGE) {
2994      fontSizeLevel = 3
2995    } else if (fontScaled < FontSizeScaleThreshold.LEVEL_3_LARGE) {
2996      fontSizeLevel = 4
2997    } else {
2998      fontSizeLevel = 1
2999    }
3000
3001    return fontSizeLevel
3002  }
3003  // Obtain the font size level, which ranges from 0 to 4.
3004  public getmarginLevel(Width: number) {
3005    let marginlevel: number = 1
3006    if (Width == 40) {
3007      marginlevel = 2.0
3008    } else if (Width == 80) {
3009      marginlevel = 1.0
3010    } else if (Width == 120) {
3011      marginlevel = 2/3
3012    } else if (Width == 160) {
3013      marginlevel = 0.5
3014    } else if (Width == 200) {
3015      marginlevel = 0.4
3016    }
3017    return marginlevel
3018  }
3019
3020  public genStrMark(fontSize: number, str: string): PixelMap {
3021    this.offContext = this.offscreenCanvas.getContext("2d", this.settings)
3022    this.clearCanvas()
3023    this.offContext.font = fontSize + 'vp sans-serif'
3024    this.offContext.fillText(str + '.', 0, fontSize * 0.9)
3025    return this.offContext.getPixelMap(0, 0, fontSize * (str.length + 1) / 1.75, fontSize)
3026  }
3027
3028  public genSquareMark(fontSize: number): PixelMap {
3029    this.offContext = this.offscreenCanvas.getContext("2d", this.settings)
3030    this.clearCanvas()
3031    const coordinate = fontSize * (1 - 1 / 1.5) / 2
3032    const sideLength = fontSize / 1.5
3033    this.offContext.fillRect(coordinate, coordinate, sideLength, sideLength)
3034    return this.offContext.getPixelMap(0, 0, fontSize, fontSize)
3035  }
3036
3037  // Generate a circle symbol.
3038  public genCircleMark(fontSize: number, width: number, level?: number ): PixelMap {
3039    const indentLevel = level ?? 1
3040    const offsetLevel = [22, 28, 32, 34, 38]
3041    const fontSizeLevel = this.getFontSizeLevel(fontSize)
3042    const marginlevel = this.getmarginLevel(width)
3043    const newCanvas = new OffscreenCanvas(canvasWidth, canvasHeight)
3044    const newOffContext: OffscreenCanvasRenderingContext2D = newCanvas.getContext("2d", this.settings)
3045    const centerCoordinate = 50
3046    const radius = 10
3047    this.clearCanvas()
3048    newOffContext.ellipse(100 * (indentLevel + 1) - centerCoordinate * marginlevel, offsetLevel[fontSizeLevel], radius * marginlevel, radius, 0, 0, 2 * Math.PI)
3049    newOffContext.fillStyle = '66FF0000'
3050    newOffContext.fill()
3051    return newOffContext.getPixelMap(0, 0, 100 + 100 * indentLevel, 100)
3052  }
3053
3054  private clearCanvas() {
3055    this.offContext.clearRect(0, 0, canvasWidth, canvasHeight)
3056  }
3057}
3058
3059@Entry
3060@Component
3061struct Index {
3062  controller: RichEditorController = new RichEditorController()
3063  options: RichEditorOptions = { controller: this.controller }
3064  private leadingMarkCreatorInstance = LeadingMarginCreator.instance
3065  private fontNameRawFile: string = 'MiSans-Bold'
3066  @State fs: number = 30
3067  @State cl: number = Color.Black
3068  private leftMargin: Dimension = 0
3069  private richEditorTextStyle: RichEditorTextStyle = {}
3070
3071  aboutToAppear() {
3072    font.registerFont({
3073      familyName: 'MiSans-Bold',
3074      familySrc: '/font/MiSans-Bold.ttf'
3075    })
3076  }
3077
3078  build() {
3079    Scroll() {
3080      Column() {
3081        RichEditor(this.options)
3082          .onReady(() => {
3083            this.controller.addTextSpan("0123456789\n",
3084              {
3085                style:
3086                {
3087                  fontWeight: 'medium',
3088                  fontFamily: this.fontNameRawFile,
3089                  fontColor: Color.Red,
3090                  fontSize: 50,
3091                  fontStyle: FontStyle.Italic,
3092                  decoration: { type: TextDecorationType.Underline, color: Color.Green }
3093                }
3094              })
3095
3096            this.controller.addTextSpan("abcdefg",
3097              {
3098                style:
3099                {
3100                  fontWeight: FontWeight.Lighter,
3101                  fontFamily: 'HarmonyOS Sans',
3102                  fontColor: 'rgba(0,128,0,0.5)',
3103                  fontSize: 30,
3104                  fontStyle: FontStyle.Normal,
3105                  decoration: { type: TextDecorationType.Overline, color: 'rgba(169, 26, 246, 0.50)' }
3106                }
3107              })
3108          })
3109          .borderWidth(1)
3110          .borderColor(Color.Green)
3111          .width("100%")
3112          .height("50%")
3113
3114        Row({ space: 5 }) {
3115          Button('setTypingStyle1')
3116            .fontSize(10)
3117            .onClick(() => {
3118              this.controller.setTypingStyle(
3119                {
3120                  fontWeight: 'medium',
3121                  fontFamily: this.fontNameRawFile,
3122                  fontColor: Color.Blue,
3123                  fontSize: 50,
3124                  fontStyle: FontStyle.Italic,
3125                  decoration: { type: TextDecorationType.Underline, color: Color.Green }
3126                })
3127            })
3128
3129          Button('setTypingStyle2')
3130            .fontSize(10)
3131            .onClick(() => {
3132              this.controller.setTypingStyle(
3133                {
3134                  fontWeight: FontWeight.Lighter,
3135                  fontFamily: 'HarmonyOS Sans',
3136                  fontColor: Color.Green,
3137                  fontSize: '30',
3138                  fontStyle: FontStyle.Normal,
3139                  decoration: { type: TextDecorationType.Overline, color: 'rgba(169, 26, 246, 0.50)' }
3140                })
3141            })
3142        }
3143        Divider()
3144        Button("getTypingStyle").onClick(() => {
3145          this.richEditorTextStyle = this.controller.getTypingStyle()
3146          console.log("RichEditor getTypingStyle:" + JSON.stringify(this.richEditorTextStyle))
3147        })
3148        Divider()
3149        Row({ space: 5 }) {
3150          Button ("Increase Bullet Indent").onClick(() => {
3151            let margin = Number(this.leftMargin)
3152            if (margin < 200) {
3153              margin += Indentation
3154              this.leftMargin = margin
3155            }
3156            this.controller.updateParagraphStyle({
3157              start: -10,
3158              end: -10,
3159              style: {
3160                leadingMargin : {
3161                  pixelMap : this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1),
3162                  size: [margin, 40]
3163                }
3164              }
3165            })
3166          })
3167
3168          Button("Decrease Bullet Indent").onClick(() => {
3169            let margin = Number(this.leftMargin)
3170            if (margin > 0) {
3171              margin -= Indentation
3172              this.leftMargin = margin
3173            }
3174            this.controller.updateParagraphStyle({
3175              start: -10,
3176              end: -10,
3177              style: {
3178                leadingMargin : {
3179                  pixelMap : this.leadingMarkCreatorInstance.genCircleMark(100, margin, 1),
3180                  size: [margin, 40]
3181                }
3182              }
3183            })
3184          })
3185        }
3186        Divider()
3187        Row({ space: 5 }) {
3188          Button ("Increase Indent").onClick(() => {
3189            let margin = Number(this.leftMargin)
3190            if (margin < 200) {
3191              margin += Indentation
3192              this.leftMargin = margin
3193            }
3194            this.controller.updateParagraphStyle({
3195              start: -10,
3196              end: -10,
3197              style: {
3198                leadingMargin: margin
3199              }
3200            })
3201          })
3202
3203          Button("Decrease Indent").onClick(() => {
3204            let margin = Number(this.leftMargin)
3205            if (margin > 0) {
3206              margin -= Indentation
3207              this.leftMargin = margin
3208            }
3209            this.controller.updateParagraphStyle({
3210              start: -10,
3211              end: -10,
3212              style: {
3213                leadingMargin: margin
3214              }
3215            })
3216          })
3217        }
3218      }.borderWidth(1).borderColor(Color.Red)
3219    }
3220  }
3221}
3222```
3223![UpdateParagraphAndTypingStyle](figures/richEditorUpdateParagraphAndTypingStyle.gif)
3224
3225### Example 8
3226``` ts
3227@Entry
3228@Component
3229struct Index {
3230  controller: RichEditorController = new RichEditorController();
3231  options: RichEditorOptions = { controller: this.controller };
3232  private start: number = -1;
3233  private end: number = -1;
3234  @State message: string = "[-1, -1]"
3235  @State content: string = ""
3236  @State visable :number = 0;
3237  @State index:number = 0;
3238  @State offsetx: number = 0;
3239  @State textShadows : (ShadowOptions | Array<ShadowOptions> ) =
3240    [{ radius: 10, color: Color.Red, offsetX: 10, offsetY: 0 },{ radius: 10, color: Color.Black, offsetX: 20, offsetY: 0 },
3241      { radius: 10, color: Color.Brown, offsetX: 30, offsetY: 0 },{ radius: 10, color: Color.Green, offsetX: 40, offsetY: 0 },
3242      { radius: 10, color: Color.Yellow, offsetX: 100, offsetY: 0 }]
3243  @State textshadowOf : ShadowOptions[] = []
3244  build() {
3245    Column() {
3246      Column() {
3247        Text("selection range:").width("100%")
3248        Text() {
3249          Span(this.message)
3250        }.width("100%")
3251        Text("selection content:").width("100%")
3252        Text() {
3253          Span(this.content)
3254        }.width("100%")
3255      }
3256      .borderWidth(1)
3257      .borderColor(Color.Red)
3258      .width("100%")
3259      .height("20%")
3260      Row() {
3261        Button("Update Style: Bold & Text Shadow").onClick(() => {
3262          this.controller.updateSpanStyle({
3263            start: this.start,
3264            end: this.end,
3265            textStyle:
3266            {
3267              fontWeight: FontWeight.Bolder,
3268              textShadow: this.textShadows
3269            }
3270          })
3271        })
3272      }
3273      .borderWidth(1)
3274      .borderColor(Color.Red)
3275      .width("100%")
3276      .height("10%")
3277      Column() {
3278        RichEditor(this.options)
3279          .onReady(() => {
3280            this.controller.addTextSpan("0123456789",
3281              {
3282                style:
3283                {
3284                  fontColor: Color.Orange,
3285                  fontSize: 30,
3286                  textShadow: { radius: 10, color: Color.Blue, offsetX: 10, offsetY: 0 }
3287                }
3288              })
3289          })
3290          .borderWidth(1)
3291          .borderColor(Color.Green)
3292          .width("100%")
3293          .height("30%")
3294      }
3295      .borderWidth(1)
3296      .borderColor(Color.Red)
3297      .width("100%")
3298      .height("70%")
3299    }
3300  }
3301}
3302```
3303
3304![TextshadowExample](figures/rich_editor_textshadow.gif)
3305
3306### Example 9
3307``` ts
3308@Builder
3309function placeholderBuilder2() {
3310  Row({ space: 2 }) {
3311    Image($r("app.media.icon")).width(24).height(24).margin({ left: -5 })
3312    Text('okokokok').fontSize(10)
3313  }.width('20%').height(50).padding(10).backgroundColor(Color.Red)
3314}
3315
3316// xxx.ets
3317@Entry
3318@Component
3319struct Index {
3320  controller: RichEditorController = new RichEditorController();
3321  option: RichEditorOptions = { controller: this.controller };
3322  private start: number = 2;
3323  private end: number = 4;
3324  @State message: string = "[-1, -1]"
3325  @State content: string = ""
3326  private my_offset: number | undefined = undefined
3327  private my_builder: CustomBuilder = undefined
3328
3329  @Builder
3330  placeholderBuilder() {
3331    Row({ space: 2 }) {
3332      Image($r("app.media.icon")).width(24).height(24).margin({ left: -5 })
3333      Text('Custom Popup').fontSize(10)
3334    }.width(100).height(50).padding(5)
3335  }
3336
3337  @Builder
3338  placeholderBuilder3() {
3339    Text("hello").padding('20').borderWidth(1).width('100%')
3340  }
3341
3342  @Builder
3343  placeholderBuilder4() {
3344    Column() {
3345      Column({ space: 5 }) {
3346        Text('direction:Row').fontSize(9).fontColor(0xCCCCCC).width('90%')
3347        Flex({ direction: FlexDirection.Row }) { // The child components are arranged in the same direction as the main axis runs along the rows.
3348          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3349          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3350          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3351          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3352        }
3353        .height(70)
3354        .width('90%')
3355        .padding(10)
3356        .backgroundColor(0xAFEEEE)
3357
3358        Text('direction:RowReverse').fontSize(9).fontColor(0xCCCCCC).width('90%')
3359        Flex({ direction: FlexDirection.RowReverse }) { // The child components are arranged opposite to the Row direction.
3360          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3361          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3362          Text('1').width('20%').height(50).backgroundColor(0xF5DEB3)
3363          Text('1').width('20%').height(50).backgroundColor(0xD2B48C)
3364        }
3365        .height(70)
3366        .width('90%')
3367        .padding(10)
3368        .backgroundColor(0xAFEEEE)
3369
3370        Text('direction:Column').fontSize(9).fontColor(0xCCCCCC).width('90%')
3371        Flex({ direction: FlexDirection.Column }) { // The child components are arranged in the same direction as the main axis runs down the columns.
3372          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3373          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3374          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3375          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3376        }
3377        .height(160)
3378        .width('90%')
3379        .padding(10)
3380        .backgroundColor(0xAFEEEE)
3381
3382        Text('direction:ColumnReverse').fontSize(9).fontColor(0xCCCCCC).width('90%')
3383        Flex({ direction: FlexDirection.ColumnReverse }) { // The child components are arranged opposite to the Column direction.
3384          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3385          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3386          Text('1').width('20%').height(40).backgroundColor(0xF5DEB3)
3387          Text('1').width('20%').height(40).backgroundColor(0xD2B48C)
3388        }
3389        .height(160)
3390        .width('90%')
3391        .padding(10)
3392        .backgroundColor(0xAFEEEE)
3393      }.width('100%').margin({ top: 5 })
3394    }.width('100%')
3395  }
3396
3397  @Builder
3398  MyMenu() {
3399    Menu() {
3400      MenuItem({ startIcon: $r("app.media.icon"), content: "Menu option 1" })
3401      MenuItem({ startIcon: $r("app.media.icon"), content: "Menu option 2" })
3402        .enabled(false)
3403    }
3404  }
3405
3406  build() {
3407    Column() {
3408      Column() {
3409        Text("selection range:").width("100%")
3410        Text() {
3411          Span(this.message)
3412        }.width("100%")
3413
3414        Text("selection content:").width("100%")
3415        Text() {
3416          Span(this.content)
3417        }.width("100%")
3418      }
3419      .borderWidth(1)
3420      .borderColor(Color.Red)
3421      .width("100%")
3422      .height("20%")
3423
3424      Row() {
3425        Button ("Get Span Info").onClick () => {
3426          console.info('getSpans='+JSON.stringify(this.controller.getSpans({ start:1, end:5 })))
3427          console.info('getParagraphs='+JSON.stringify(this.controller.getParagraphs({ start:1, end:5 })))
3428          this.content = ""
3429          this.controller.getSpans({
3430            start: this.start,
3431            end: this.end
3432          }).forEach(item => {
3433            if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
3434              if ((item as RichEditorImageSpanResult).valueResourceStr == "") {
3435                console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " +
3436                  (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1])
3437              } else {
3438                console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " +
3439                  (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " +
3440                  (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1])
3441              }
3442            } else {
3443              this.content += (item as RichEditorTextSpanResult).value;
3444              this.content += "\n"
3445              console.info("text span: " + (item as RichEditorTextSpanResult).value)
3446            }
3447          })
3448        })
3449        Button ("Get Selection").onClick () => {
3450          this.content = "";
3451          let select = this.controller.getSelection()
3452          console.info("selection start " + select.selection[0] + " end " + select.selection[1])
3453          select.spans.forEach(item => {
3454            if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
3455              if ((item as RichEditorImageSpanResult).valueResourceStr == "") {
3456                console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " +
3457                  (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1])
3458              } else {
3459                console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " +
3460                  (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " +
3461                  (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1])
3462              }
3463            } else {
3464              this.content += (item as RichEditorTextSpanResult).value;
3465              this.content += "\n"
3466              console.info("text span: " + (item as RichEditorTextSpanResult).value)
3467            }
3468          })
3469        })
3470        Button("Delete Selection").onClick(() => {
3471          this.controller.deleteSpans({
3472            start: this.start,
3473            end: this.end
3474          })
3475        })
3476      }
3477      .borderWidth(1)
3478      .borderColor(Color.Red)
3479      .width("100%")
3480      .height("10%")
3481
3482      Column() {
3483        RichEditor(this.option)
3484          .onReady(() => {
3485            this.controller.addTextSpan("0123456789",
3486              {
3487                style:
3488                {
3489                  fontColor: Color.Orange,
3490                  fontSize: 30
3491                }
3492              })
3493            this.controller.addImageSpan($r("app.media.icon"),
3494              {
3495                imageStyle:
3496                {
3497                  size: ["57px", "57px"]
3498                }
3499              })
3500          })
3501          .onSelect((value: RichEditorSelection) => {
3502            this.start = value.selection[0];
3503            this.end = value.selection[1];
3504            this.message = "[" + this.start + ", " + this.end + "]"
3505            console.info("onSelect="+JSON.stringify(value))
3506          })
3507          .aboutToIMEInput((value: RichEditorInsertValue) => {
3508            console.log("---------------------- aboutToIMEInput --------------------")
3509            console.info("aboutToIMEInput="+JSON.stringify(value))
3510            console.log("insertOffset:" + value.insertOffset)
3511            console.log("insertValue:" + value.insertValue)
3512            return true;
3513          })
3514          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
3515            console.log("---------------------- onIMEInputComplete --------------------")
3516            console.info("onIMEInputComplete="+JSON.stringify(value))
3517            console.log("spanIndex:" + value.spanPosition.spanIndex)
3518            console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]")
3519            console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]")
3520            console.log("value:" + value.value)
3521          })
3522          .aboutToDelete((value: RichEditorDeleteValue) => {
3523            value.richEditorDeleteSpans.forEach(item => {
3524              console.log("---------------------- item --------------------")
3525              console.info("spanIndex=" + item.spanPosition.spanIndex)
3526              console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]")
3527              console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]")
3528              if (typeof (item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
3529                if ((item as RichEditorImageSpanResult).valueResourceStr == "") {
3530                  console.info("builder span index " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range : " + (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " +
3531                  (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " + (item as RichEditorImageSpanResult).imageStyle[0] + ", " + (item as RichEditorImageSpanResult).imageStyle[1])
3532                } else {
3533                  console.info("image span " + (item as RichEditorImageSpanResult).valueResourceStr + ", index : " + (item as RichEditorImageSpanResult).spanPosition.spanIndex + ", range: " +
3534                  (item as RichEditorImageSpanResult).offsetInSpan[0] + ", " + (item as RichEditorImageSpanResult).offsetInSpan[1] + ", size : " +
3535                  (item as RichEditorImageSpanResult).imageStyle.size[0] + ", " + (item as RichEditorImageSpanResult).imageStyle.size[1])
3536                }
3537              } else {
3538                console.info("delete text: " + (item as RichEditorTextSpanResult).value)
3539              }
3540            })
3541            return true;
3542          })
3543          .borderWidth(1)
3544          .borderColor(Color.Green)
3545          .width("100%")
3546          .height("30%")
3547
3548        Button("add span")
3549          .onClick(() => {
3550            let num = this.controller.addBuilderSpan(this.my_builder, { offset: this.my_offset })
3551            console.info('addBuilderSpan return ' + num)
3552          })
3553        Button("add image")
3554          .onClick(() => {
3555            let num = this.controller.addImageSpan($r("app.media.icon"), {
3556              imageStyle: {
3557                size: ["50px", "50px"],
3558                verticalAlign: ImageSpanAlignment.BOTTOM,
3559                layoutStyle: {
3560                  borderRadius: undefined,
3561                  margin: undefined
3562                }
3563              }
3564            })
3565            console.info('addImageSpan return' + num)
3566          })
3567        Row() {
3568          Button('builder1').onClick(() => {
3569            this.my_builder = () => {
3570              this.placeholderBuilder()
3571            }
3572          })
3573          Button('builder2').onClick(() => {
3574            this.my_builder = placeholderBuilder2.bind(this)
3575          })
3576          Button('builder3').onClick(() => {
3577            this.my_builder = () => {
3578              this.placeholderBuilder3()
3579            }
3580          })
3581          Button('builder4').onClick(() => {
3582            this.my_builder = () => {
3583              this.placeholderBuilder4()
3584            }
3585          })
3586        }
3587      }
3588      .borderWidth(1)
3589      .borderColor(Color.Red)
3590      .width("100%")
3591      .height("70%")
3592    }
3593  }
3594}
3595```
3596![AddBuilderSpanExample](figures/rich_editor_addBuilderSpan.gif)
3597
3598### Example 10
3599Example of using **enableDataDetector** and **dataDetectorConfig**
3600
3601```ts
3602@Entry
3603@Component
3604struct TextExample7 {
3605  controller: RichEditorController = new RichEditorController();
3606  options: RichEditorOptions = { controller: this.controller };
3607  @State phoneNumber: string = '(86) (755) ********';
3608  @State url: string = 'www.********.com';
3609  @State email: string = '***@example.com';
3610  @State address: string = 'Street A, city B, state C';
3611  @State enableDataDetector: boolean = true;
3612  @State enablePreviewText: boolean = false;
3613  @State types: TextDataDetectorType[] = [];
3614
3615  build() {
3616    Row() {
3617      Column() {
3618        RichEditor(this.options)
3619          .onReady(() => {
3620            this.controller.addTextSpan('Phone number:' + this.phoneNumber + '\n',
3621              {
3622                style:
3623                {
3624                  fontSize: 30
3625                }
3626              })
3627            this.controller.addTextSpan('URL:' + this.url + '\n',
3628              {
3629                style:
3630                {
3631                  fontSize: 30
3632                }
3633              })
3634            this.controller.addTextSpan('Email:' + this.email + '\n',
3635              {
3636                style:
3637                {
3638                  fontSize: 30
3639                }
3640              })
3641            this.controller.addTextSpan('Address:' + this.address,
3642              {
3643                style:
3644                {
3645                  fontSize: 30
3646                }
3647              })
3648          })
3649          .copyOptions(CopyOptions.InApp)
3650          .enableDataDetector(this.enableDataDetector)
3651          .dataDetectorConfig({types : this.types, onDetectResultUpdate: (result: string)=>{}})
3652          .enablePreviewText(this.enablePreviewText)
3653          .borderWidth(1)
3654          .padding(10)
3655          .width('100%')
3656      }
3657      .width('100%')
3658    }
3659  }
3660}
3661```
3662### Example 11
3663This example shows how to use **caretColor** and **selectedBackgroundColor**.
3664``` ts
3665@Entry
3666@Component
3667struct RichEditorDemo {
3668  @State color: Color|string = ""
3669  controller: RichEditorController = new RichEditorController();
3670  build() {
3671    Column() {
3672      Row(){
3673        Button("Change to Red").onClick(() => {
3674          this.color = Color.Red
3675        })
3676      }.margin({top:50})
3677      RichEditor({ controller: this.controller })
3678        .onReady(()=>{
3679          this.controller.addTextSpan('This is for testing')
3680        })
3681        .width("100%")
3682        .border({ width: 1, radius: 5 })
3683        .key('RichEditor')
3684        .caretColor(this.color) // Caret color
3685        .selectedBackgroundColor(this.color) // Background color of the selected content.
3686        .margin({top:50})
3687    }
3688    .width('100%')
3689  }
3690}
3691```
3692![SetCaretAndSelectedBackgroundColorExample](figures/rich_editor_caret_color.gif)
3693
3694### Example 12
3695This example shows the usage of **lineHeight** and **letterSpacing**.
3696```ts
3697@Entry
3698@Component
3699struct RichEditorDemo03 {
3700  controller: RichEditorController = new RichEditorController();
3701  options: RichEditorOptions = { controller: this.controller };
3702  @State start: number = -1;
3703  @State end: number = -1;
3704  @State LH:number = 50
3705  @State LS:number = 20
3706
3707  build() {
3708    Column() {
3709      Scroll(){
3710        Column(){
3711          Row() {
3712            Button("Line Height ++").onClick(()=>{
3713              this.LH = this.LH + 5
3714              this.controller.updateSpanStyle({
3715                start: this.start,
3716                end: this.end,
3717                textStyle:
3718                {
3719                  lineHeight: this.LH
3720                }
3721              })
3722            })
3723            Button("Line Height --").onClick(()=>{
3724              this.LH = this.LH - 5
3725              this.controller.updateSpanStyle({
3726                start: this.start,
3727                end: this.end,
3728                textStyle:
3729                {
3730                  lineHeight: this.LH
3731                }
3732              })
3733            })
3734            Button("Letter Spacing ++").onClick (()=>{
3735              this.LS = this.LS + 5
3736              this.controller.updateSpanStyle({
3737                start: this.start,
3738                end: this.end,
3739                textStyle:
3740                {
3741                  letterSpacing: this.LS
3742                }
3743              })
3744            })
3745            Button("Letter Spacing --").onClick (()=>{
3746              this.LS = this.LS - 5
3747              this.controller.updateSpanStyle({
3748                start: this.start,
3749                end: this.end,
3750                textStyle:
3751                {
3752                  letterSpacing: this.LS
3753                }
3754              })
3755            })
3756          }
3757        }
3758      }.borderWidth(1)
3759      .borderColor(Color.Red)
3760      .width("100%")
3761      .height("20%")
3762      .margin({top: 20})
3763
3764      Scroll(){
3765        Column() {
3766          Text("LineHeight:" + this.LH).width("100%")
3767          Text("LetterSpacing:" + this.LS).width("100%")
3768        }
3769      }
3770      .borderWidth(1)
3771      .borderColor(Color.Red)
3772      .width("100%")
3773      .height("20%")
3774      .margin({bottom: 20})
3775
3776      Column() {
3777        RichEditor(this.options).clip(true).padding(10)
3778          .onReady(() => {
3779            this.controller.addTextSpan("012345",
3780              {
3781                style:
3782                {
3783                  fontColor: Color.Orange,
3784                  fontSize: 30,
3785                  lineHeight: this.LH,
3786                  letterSpacing: this.LS
3787                }
3788              })
3789            this.controller.addTextSpan("6789",
3790              {
3791                style:
3792                {
3793                  fontColor: Color.Black,
3794                  fontSize: 30,
3795                  lineHeight: this.LH,
3796                  letterSpacing: this.LS
3797                }
3798              })
3799          })
3800          .borderWidth(1)
3801          .borderColor(Color.Green)
3802          .width(400)
3803          .height(400)
3804      }
3805      .borderWidth(1)
3806      .borderColor(Color.Red)
3807      .width("100%")
3808      .height("60%")
3809    }
3810  }
3811}
3812```
3813![AddBuilderSpanExample](figures/richEditorLineHeightAndLetterSpacing.png)
3814
3815### Example 13
3816This example shows the usage of **preventDefault**.
3817```ts
3818@Entry
3819@Component
3820struct RichEditorDemo {
3821  controller: RichEditorController = new RichEditorController();
3822  options: RichEditorOptions = { controller: this.controller };
3823
3824  build() {
3825    Column({ space: 2 }) {
3826      RichEditor(this.options)
3827        .onReady(() => {
3828          this.controller.addTextSpan('RichEditor preventDefault')
3829        })
3830        .onPaste((event?: PasteEvent) => {
3831          if (event != undefined && event.preventDefault) {
3832            event.preventDefault();
3833          }
3834        })
3835        .borderWidth(1)
3836        .borderColor(Color.Green)
3837        .width('100%')
3838        .height('40%')
3839    }
3840  }
3841}
3842```
3843![PreventDefaultExample](figures/richEditorPreventDefault.gif)
3844
3845### Example 14
3846
3847This example sets the **FontFeature** attribute to **ss01**, which changes the digit "0" from its original oval shape to a shape with rounded corners.
3848
3849```ts
3850@Entry
3851@Component
3852struct RichEditorExample {
3853  controller: RichEditorController = new RichEditorController();
3854  options: RichEditorOptions = { controller: this.controller };
3855  @State enableDataDetector: boolean = true;
3856  @State types: TextDataDetectorType[] = [];
3857  build() {
3858    Row() {
3859      Column() {
3860        RichEditor(this.options)
3861          .onReady(() => {
3862            this.controller.addTextSpan('This is ss01 off :' + '0000' + '\n',
3863              {
3864                style:
3865                {
3866                  fontSize: 30
3867                }
3868              })
3869            this.controller.addTextSpan('This is ss01 on :' + '0000' + '\n',
3870              {
3871                style:
3872                {
3873                  fontSize: 30,
3874                  fontFeature: "\"ss01\" 1"
3875                }
3876              })
3877          })
3878          .copyOptions(CopyOptions.InApp)
3879          .enableDataDetector(this.enableDataDetector)
3880          .dataDetectorConfig({types : this.types, onDetectResultUpdate: (result: string)=>{}})
3881          .borderWidth(1)
3882          .padding(10)
3883          .width('100%')
3884      }
3885      .width('100%')
3886      .margin({top:150})
3887    }
3888  }
3889}
3890```
3891![FontFeatureExample](figures/richEditorFontFeature.png)
3892
3893### Example 15
3894
3895This example shows how to support custom keyboard avoidance.
3896
3897```ts
3898@Entry
3899@Component
3900struct RichEditorExample {
3901  controller: RichEditorController = new RichEditorController()
3902  @State height1:string|number = '80%'
3903  @State height2:number = 100
3904  @State supportAvoidance:boolean = true;
3905
3906  // Create a custom keyboard component.
3907  @Builder CustomKeyboardBuilder() {
3908    Column() {
3909      Row(){
3910        Button('Add Emoticon').onClick(() => {
3911          this.controller.addTextSpan("\uD83D\uDE0A",
3912            {
3913              style:
3914              {
3915                fontColor: Color.Orange,
3916              }
3917            })
3918        })
3919      }
3920      Grid() {
3921        ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, '*', 0, '#'], (item: number | string) => {
3922          GridItem() {
3923            Button(item + "")
3924              .width(110).onClick(() => {
3925              this.controller.addTextSpan(item + '', {
3926                offset: this.controller.getCaretOffset(),
3927                style:
3928                {
3929                  fontColor: Color.Orange,
3930                  fontSize: 30
3931                }
3932              })
3933              this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length)
3934            })
3935          }
3936        })
3937      }.maxCount(3).columnsGap(10).rowsGap(10).padding(5)
3938    }.backgroundColor(Color.Gray)
3939  }
3940
3941  build() {
3942    Column() {
3943      Row(){
3944        Button("20%")
3945          .fontSize(24)
3946          .onClick(()=>{
3947            this.height1 = "20%"
3948          })
3949        Button("80%")
3950          .fontSize(24)
3951          .margin({left:20})
3952          .onClick(()=>{
3953            this.height1 = "80%"
3954          })
3955      }
3956      .justifyContent(FlexAlign.Center)
3957      .alignItems(VerticalAlign.Bottom)
3958      .height(this.height1)
3959      .width("100%")
3960      .padding({bottom:50})
3961      RichEditor({ controller: this.controller })
3962        // Bind the custom keyboard.
3963        .customKeyboard(this.CustomKeyboardBuilder(),{ supportAvoidance: this.supportAvoidance }).margin(10).border({ width: 1 })
3964        .borderWidth(1)
3965        .borderColor(Color.Red)
3966        .width("100%")
3967    }
3968  }
3969}
3970```
3971![CustomRichEditorType](figures/Custom_Rich_Editor.gif)
3972
3973### Example 16
3974
3975This example shows the usage of **onEditingChange** and **isEditing**.
3976
3977```ts
3978@Entry
3979@Component
3980struct RichEditor_onEditingChange {
3981  controller: RichEditorController = new RichEditorController()
3982  @State controllerIsEditing: boolean = false
3983  @Builder
3984
3985  build() {
3986    Column() {
3987      Row() {
3988        Button("View Editing State: isEditing():").onClick(() => {
3989          this.controllerIsEditing = this.controller.isEditing()
3990        })
3991          .padding(5)
3992        Text('' + this.controllerIsEditing)
3993          .width('100%')
3994          .padding(5)
3995          .fontColor(Color.Orange)
3996          .fontSize(20)
3997      }
3998      RichEditor({ controller: this.controller })
3999        .onEditingChange((isEditing: boolean) => {
4000          console.log("Current Editing Status:" + isEditing)
4001        })
4002        .height(400)
4003        .borderWidth(1)
4004        .borderColor(Color.Red)
4005        .width("100%")
4006    }
4007  }
4008}
4009```
4010
4011![RichEditorOnEditingChange](figures/richEditorOnEditingChange.gif)
4012
4013### Example 17
4014
4015This example shows the usage of **onWillChange**, **onDidChange**, **onCut**, and **onCopy**.
4016
4017```ts
4018@Entry
4019@Component
4020struct RichEditorExample {
4021  controller: RichEditorController = new RichEditorController()
4022  build() {
4023    Column() {
4024      RichEditor({ controller: this.controller })
4025        .height(200)
4026        .borderWidth(1)
4027        .borderColor(Color.Red)
4028        .width("100%")
4029        .onReady(() => {
4030          this.controller.addTextSpan('TestWord', { style: { fontColor: Color.Orange, fontSize: 30 } })
4031          this.controller.updateSpanStyle({
4032            start: -1,
4033            end: -1,
4034            textStyle:
4035            {
4036              fontWeight: FontWeight.Bolder
4037            }
4038          })
4039        })
4040        .onWillChange((value: RichEditorChangeValue) => {
4041          console.log('Test log: onWillChange')
4042          console.log('rangeBefore: ' + JSON.stringify(value.rangeBefore))
4043          console.log('print replacedSpans')
4044          value.replacedSpans.forEach((item: RichEditorTextSpanResult) => {
4045            console.log('spanPosition:' + JSON.stringify(item.spanPosition))
4046            console.log('value:' + item.value)
4047            console.log('textStyle:' + JSON.stringify(item.textStyle))
4048            console.log('offsetInSpan:' + item.offsetInSpan)
4049            console.log('valueResource:' + item.valueResource)
4050            console.log('paragraphStyle:' + JSON.stringify(item.paragraphStyle))
4051          })
4052          console.log('print replacedImageSpans')
4053          value.replacedImageSpans.forEach((item: RichEditorImageSpanResult) => {
4054            console.log('spanPosition:' + JSON.stringify(item.spanPosition))
4055            console.log('valuePixelMap:' + JSON.stringify(item.valuePixelMap))
4056            console.log('valueResourceStr:' + item.valueResourceStr)
4057            console.log('imageStyle:' + JSON.stringify(item.imageStyle))
4058            console.log('offsetInSpan:' + item.offsetInSpan)
4059          })
4060          console.log('print replacedSymbolSpans')
4061          value.replacedSymbolSpans.forEach((item: RichEditorTextSpanResult) => {
4062            console.log('spanPosition:' + JSON.stringify(item.spanPosition))
4063            console.log('value:' + item.value)
4064            console.log('offsetInSpan:' + item.offsetInSpan)
4065            console.log('symbolSpanStyle:' + JSON.stringify(item.symbolSpanStyle))
4066            console.log('valueResource:' + item.valueResource)
4067            console.log('paragraphStyle:' + JSON.stringify(item.paragraphStyle))
4068          })
4069          return true
4070        })
4071        .onDidChange((rangeBefore: TextRange, rangeAfter: TextRange) => {
4072          console.log('Test log: onDidChange')
4073          console.log('rangeBefore:' + JSON.stringify(rangeBefore))
4074          console.log('rangeAfter:' + JSON.stringify(rangeAfter))
4075        })
4076        .onCut((event:CutEvent) => {
4077          event.preventDefault!()
4078          console.log('Test log: onCut')
4079        })
4080        .onCopy((event:CopyEvent) => {
4081          event.preventDefault!()
4082          console.log('Test log: onCopy')
4083        })
4084        .onPaste(()=>{
4085          console.log('Test log: onPaste')
4086        })
4087      Text ('Test text Hello')
4088        .lineHeight(50)
4089        .fontSize(24)
4090        .draggable(true)
4091        .onDragStart(()=>{})
4092      TextInput({text:'Test text NiHao'})
4093        .draggable(true)
4094        .margin(20)
4095    }
4096  }
4097}
4098```
4099### Example 18
4100
4101This example shows the usage of **enterKeyType**, **onSubmit**, and **stopEditing**.
4102
4103```ts
4104@Entry
4105@Component
4106struct SoftKeyboardEnterTypeExample {
4107  controller: RichEditorController = new RichEditorController()
4108
4109    build() {
4110    Column() {
4111      Button("Stop Editing").onClick(()=>{
4112        this.controller.stopEditing()
4113      })
4114      RichEditor({ controller: this.controller })
4115        .margin(10)
4116        .border({ width: 1 })
4117        .height(200)
4118        .borderWidth(1)
4119        .borderColor(Color.Red)
4120        .width("100%")
4121        .enterKeyType(EnterKeyType.Search)
4122        .onSubmit((enterKey: EnterKeyType, event: SubmitEvent) => {
4123          console.log("trigger richeditor onsubmit" + enterKey);
4124          this.controller.addTextSpan(" type["+ enterKey +"] triggerred")
4125          event.keepEditableState();
4126        })
4127    }.height("100%").justifyContent(FlexAlign.Center)
4128  }
4129}
4130```
4131
4132![SoftKeyboardEnterType](figures/richeditorentertype.gif)
4133
4134### Example 19
4135This example demonstrates how to set, update, and query the value of **lineBreakStrategy**.
4136
4137```ts
4138@Entry
4139@Component
4140struct LineBreakStrategyExample {
4141  controller: RichEditorController = new RichEditorController();
4142  private spanParagraphs: RichEditorParagraphResult[] = [];
4143  @State lineBreakOptionStr: string[] = ['GREEDY', 'HIGH_QUALITY', 'BALANCED']
4144  @State attributeValue: string = ""
4145  @State testStr: string = "0123456789,0123456789,0123456789,0123456789,0123456789."
4146  build() {
4147    Column() {
4148      RichEditor({ controller: this.controller })
4149        .onReady(() => {
4150          this.controller.addTextSpan(this.testStr, {
4151            style: {
4152              fontColor: Color.Black,
4153              fontSize: "32",
4154            },
4155            paragraphStyle: {
4156              textAlign: TextAlign.Start,
4157              lineBreakStrategy: LineBreakStrategy.GREEDY
4158            }
4159          })
4160        })
4161        .width(400)
4162        .height(300)
4163        .margin({bottom:20})
4164        .draggable(false)
4165      Column(){
4166        Text('linebreak value: ' + this.attributeValue).fontSize(20).fontColor(Color.Black)
4167      }.margin({bottom: 10})
4168      Column({ space: 10 }) {
4169        Button("Set LineBreakStrategy to GREEDY").onClick(() => {
4170          this.controller.updateParagraphStyle({ start: -1, end: -1,
4171            style: {
4172              lineBreakStrategy: LineBreakStrategy.GREEDY,
4173            }
4174          })
4175        })
4176        Button("Set LineBreakStrategy to HIGH_QUALITY").onClick(() => {
4177          this.controller.updateParagraphStyle({ start: -1, end: -1,
4178            style: {
4179              lineBreakStrategy: LineBreakStrategy.HIGH_QUALITY,
4180            }
4181          })
4182        })
4183        Button("Set LineBreakStrategy to BALANCED").onClick(() => {
4184          this.controller.updateParagraphStyle({ start: -1, end: -1,
4185            style: {
4186              lineBreakStrategy: LineBreakStrategy.BALANCED,
4187            }
4188          })
4189        })
4190        Divider()
4191        Row(){
4192          Button("Get LineBreakStrategy Value").onClick(() => {
4193            this.spanParagraphs = this.controller.getParagraphs({ start: -1, end: -1 })
4194            console.log("RichEditor getParagraphs:" + JSON.stringify(this.spanParagraphs))
4195            this.spanParagraphs.forEach(item => {
4196              if(typeof(item as RichEditorParagraphResult)['style'] != 'undefined'){
4197                this.attributeValue = ""
4198                console.info('lineBreakStrategy:'+ JSON.stringify((item as RichEditorParagraphResult)['style']))
4199                this.attributeValue += this.lineBreakOptionStr[Number((item as RichEditorParagraphResult)['style'].lineBreakStrategy)];
4200              }
4201            })
4202          })
4203        }
4204      }
4205    }
4206  }
4207}
4208```
4209
4210![LineBreakStrategy](figures/richEditorLineBreak.gif)
4211
4212### Example: 20
4213This example shows the usage of a styled string.
4214
4215```ts
4216import { LengthMetrics } from '@kit.ArkUI'
4217import { image } from '@kit.ImageKit'
4218
4219@Entry
4220@Component
4221struct Index {
4222  stringLength: number = 0;
4223  imagePixelMap: image.PixelMap | undefined = undefined;
4224  @State selection: string = "";
4225  @State content: string = "";
4226  @State range: string = "";
4227  @State replaceString: string = "";
4228  @State rangeBefore: string = "";
4229  @State rangeAfter: string = "";
4230  richEditorStyledString: MutableStyledString = new MutableStyledString("");
4231  textStyle: TextStyle = new TextStyle({
4232    fontWeight: FontWeight.Lighter,
4233    fontFamily: 'HarmonyOS Sans',
4234    fontColor: Color.Green,
4235    fontSize: LengthMetrics.vp(30),
4236    fontStyle: FontStyle.Normal
4237  })
4238  fontStyle1: TextStyle = new TextStyle({ fontColor: Color.Blue });
4239  fontStyle2: TextStyle = new TextStyle({
4240    fontWeight: FontWeight.Bolder,
4241    fontFamily: 'Arial',
4242    fontColor: Color.Orange,
4243    fontSize: LengthMetrics.vp(30),
4244    fontStyle: FontStyle.Italic
4245  })
4246  // Create a styled string object.
4247  mutableStyledString: MutableStyledString = new MutableStyledString("Initial styled string",
4248    [{ start: 0, length: 5, styledKey: StyledStringKey.FONT, styledValue: this.fontStyle1 }]);
4249  styledString: StyledString = new StyledString("Styled string to insert",
4250    [{ start: 2, length: 4, styledKey: StyledStringKey.FONT, styledValue: this.fontStyle2 }]);
4251  controller: RichEditorStyledStringController = new RichEditorStyledStringController();
4252  options: RichEditorStyledStringOptions = {controller: this.controller};
4253  // Text content change callback
4254  contentChangedListener: StyledStringChangedListener = {
4255    onWillChange: (value: StyledStringChangeValue) => {
4256      this.range = '[ ' + value.range.start + ' , ' + value.range.end + ' ]';
4257      this.replaceString = value.replacementString.getString();
4258      return true;
4259    },
4260    onDidChange: (rangeBefore, rangeAfter) => {
4261      this.rangeBefore = '[ ' + rangeBefore.start + ' , ' + rangeBefore.end + ' ]';
4262      this.rangeAfter = '[ ' + rangeAfter.start + ' , ' + rangeAfter.end + ' ]';
4263    }
4264  }
4265
4266  async aboutToAppear() {
4267    console.info("aboutToAppear initial imagePixelMap");
4268    this.imagePixelMap = await this.getPixmapFromMedia($r('app.media.icon'));
4269  }
4270
4271  private async getPixmapFromMedia(resource: Resource) {
4272    let unit8Array = await getContext(this)?.resourceManager?.getMediaContent({
4273      bundleName: resource.bundleName,
4274      moduleName: resource.moduleName,
4275      id: resource.id
4276    })
4277    let imageSource = image.createImageSource(unit8Array.buffer.slice(0, unit8Array.buffer.byteLength))
4278    let createPixelMap: image.PixelMap = await imageSource.createPixelMap({
4279      desiredPixelFormat: image.PixelMapFormat.RGBA_8888
4280    })
4281    await imageSource.release()
4282    return createPixelMap
4283  }
4284
4285
4286  build() {
4287    Column() {
4288      Column() {
4289        Text("Selection information")
4290          .fontSize(20)
4291          .width("100%")
4292        Text("selection range: " + this.selection).width("100%")
4293        Text("selection content: " + this.content).width("100%")
4294      }
4295      .borderWidth(1)
4296      .borderColor(Color.Black)
4297      .width("100%")
4298      .height("10%")
4299
4300      Column() {
4301        Text("onWillChange callback")
4302          .fontSize(20)
4303          .width("100%")
4304        Text("range: " + this.range).width("100%")
4305        Text("replacementString: " + this.replaceString).width("100%")
4306        Tex ("onWillChange callback")
4307          .fontSize(20)
4308          .width("100%")
4309        Text("rangeBefore: " + this.rangeBefore).width("100%")
4310        Text("rangeAfter: " + this.rangeAfter).width("100%")
4311      }
4312      .borderWidth(1)
4313      .borderColor(Color.Black)
4314      .width("100%")
4315      .height("20%")
4316
4317      RichEditor(this.options)
4318        .onReady(() => {
4319          // Register a text change callback.
4320          this.controller.onContentChanged(this.contentChangedListener);
4321          // Set the styled string displayed in the component.
4322          this.controller.setStyledString(this.mutableStyledString);
4323        })
4324        .height("20%")
4325        .width("100%")
4326        .borderWidth(1)
4327        .borderColor(Color.Black)
4328
4329      Column() {
4330        Row() {
4331          Button("Insert Image").onClick () => {
4332            if (this.imagePixelMap !== undefined) {
4333              let imageStyledString = new MutableStyledString(new ImageAttachment({
4334                value: this.imagePixelMap,
4335                size: { width: 50, height: 50 },
4336                layoutStyle: { borderRadius: LengthMetrics.vp(10) },
4337                verticalAlign: ImageSpanAlignment.BASELINE,
4338                objectFit: ImageFit.Contain
4339              }))
4340              // Obtain the styled string displayed in the component.
4341              this.richEditorStyledString = this.controller.getStyledString();
4342              this.richEditorStyledString.appendStyledString(imageStyledString);
4343              // Display the styled string after the image is inserted on the component.
4344              this.controller.setStyledString(this.richEditorStyledString);
4345              this.controller.setCaretOffset(this.richEditorStyledString.length);
4346            }
4347          })
4348          Button("Insert Text").onClick () => {
4349              // Obtain the styled string displayed in the component.
4350              this.richEditorStyledString = this.controller.getStyledString();
4351              this.richEditorStyledString.appendStyledString(this.styledString);
4352              // Display the styled string after the text is inserted on the component.
4353              this.controller.setStyledString(this.richEditorStyledString);
4354              this.controller.setCaretOffset(this.richEditorStyledString.length);
4355          })
4356        }
4357        Row() {
4358          Button("Get Selection").onClick(() => {
4359            // Obtain the selection.
4360            let richEditorSelection = this.controller.getSelection();
4361            let start = richEditorSelection.start ? richEditorSelection.start : 0;
4362            let end = richEditorSelection.end ? richEditorSelection.end : 0;
4363            // Obtain the styled string displayed in the component.
4364            this.richEditorStyledString = this.controller.getStyledString();
4365            this.selection = '[ ' + start + ' , ' + end + ' ]';
4366            if (start == end) {
4367              this.content = "";
4368            } else {
4369              this.content = this.richEditorStyledString.subStyledString(start, end - start).getString();
4370            }
4371          })
4372          Button("Update Selection Style").onClick () => {
4373            // Obtain the selection.
4374            let richEditorSelection = this.controller.getSelection();
4375            let start = richEditorSelection.start ? richEditorSelection.start : 0;
4376            let end = richEditorSelection.end ? richEditorSelection.end : 0;
4377            // Obtain the styled string displayed in the component.
4378            this.richEditorStyledString = this.controller.getStyledString();
4379            this.richEditorStyledString.setStyle({
4380              start: start,
4381              length: end - start,
4382              styledKey: StyledStringKey.FONT,
4383              styledValue: this.textStyle
4384            })
4385            // Display the styled string after the style change on the component.
4386            this.controller.setStyledString(this.richEditorStyledString);
4387          })
4388          Button("Delete Selected").onClick(() => {
4389            // Obtain the selection.
4390            let richEditorSelection = this.controller.getSelection();
4391            let start = richEditorSelection.start ? richEditorSelection.start : 0;
4392            let end = richEditorSelection.end ? richEditorSelection.end : 0;
4393            // Obtain the styled string displayed in the component.
4394            this.richEditorStyledString = this.controller.getStyledString();
4395            this.richEditorStyledString.removeString(start, end - start);
4396            // Display the styled string after the content is deleted on the component.
4397            this.controller.setStyledString(this.richEditorStyledString);
4398          })
4399        }
4400      }
4401      .width("100%")
4402    }
4403  }
4404}
4405```
4406
4407![StyledString](figures/richEditorStyledString.gif)
4408
4409### Example 21
4410This example shows the usage of **NodeAdapter**.
4411
4412```ts
4413@Entry
4414@Component
4415export struct Index {
4416  @State lineCount: string = ""
4417  @State glyphPositionAtCoordinate: string = ""
4418  @State lineMetrics: string = ""
4419  controller: RichEditorController = new RichEditorController();
4420  @State textStr: string =
4421    'Hello World!'
4422
4423  build() {
4424    Scroll() {
4425      Column() {
4426        Text('getLayoutManager obtains the layout information relative to the component')
4427          .fontSize(9)
4428          .fontColor(0xCCCCCC)
4429          .width('90%')
4430          .padding(10)
4431        RichEditor({ controller: this.controller })
4432          .borderColor(Color.Red)
4433          .borderWidth(1)
4434          .onReady(() => {
4435            this.controller.addTextSpan(this.textStr)
4436          })
4437          .onAreaChange(() => {
4438            let layoutManager = this.controller.getLayoutManager();
4439            this.lineCount = "LineCount: " + layoutManager.getLineCount()
4440          })
4441
4442        Text('LineCount').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10)
4443        Text(this.lineCount)
4444
4445        Text('GlyphPositionAtCoordinate').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10)
4446        Button("Glyph info of relative component coordinates [150, 50]")
4447          .onClick(() => {
4448            let layoutManager: LayoutManager = this.controller.getLayoutManager()
4449            let position = layoutManager.getGlyphPositionAtCoordinate(150, 50)
4450            this.glyphPositionAtCoordinate =
4451            "Relative component coordinates [150, 50] glyphPositionAtCoordinate position: " + position.position + " affinity: " +
4452            position.affinity
4453          })
4454          .margin({ bottom: 20, top: 10 })
4455        Text(this.glyphPositionAtCoordinate)
4456
4457        Text('LineMetrics').fontSize(9).fontColor(0xCCCCCC).width('90%').padding(10)
4458        Button("Line Metrics")
4459          .onClick(() => {
4460            let layoutManager: LayoutManager = this.controller.getLayoutManager()
4461            let lineMetrics = layoutManager.getLineMetrics(0)
4462            this.lineMetrics = "lineMetrics is " + JSON.stringify(lineMetrics) + '\n\n'
4463            let runMetrics = lineMetrics.runMetrics
4464            runMetrics.forEach((value, key) => {
4465              this.lineMetrics += "runMetrics key is " + key + " " + JSON.stringify(value) + "\n\n"
4466            });
4467          })
4468          .margin({ bottom: 20, top: 10 })
4469        Text(this.lineMetrics)
4470      }
4471      .margin({ top: 100, left: 8, right: 8 })
4472    }
4473  }
4474}
4475```
4476
4477![LayoutManager](figures/getLayoutManager.gif)
4478
4479### Example: 22
4480
4481This example shows how to set **editMenuOptions**.
4482
4483```ts
4484// xxx.ets
4485@Entry
4486@Component
4487struct RichEditorExample {
4488  controller: RichEditorController = new RichEditorController();
4489  options: RichEditorOptions = { controller: this.controller }
4490
4491  onCreateMenu(menuItems: Array<TextMenuItem>) {
4492    console.log('menuItems size=' + menuItems.length);
4493    menuItems.forEach((value, index) => {
4494      console.log('menuItem' + index + ', id=' + JSON.stringify(value));
4495    })
4496    let extensionMenuItems: Array<TextMenuItem> = [
4497      {
4498        content: 'Extended RichEditor 1', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension1')
4499      },
4500      {
4501        content: 'Extended RichEditor 2', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension2')
4502      },
4503      {
4504        content: 'Extended RichEditor 3', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension3')
4505      },
4506      {
4507        content: 'Extended RichEditor 4', icon: $r('app.media.startIcon'), id: TextMenuItemId.of('extension4')
4508      }
4509    ]
4510    return menuItems.concat(extensionMenuItems)
4511  }
4512  onMenuItemClicked(menuItem: TextMenuItem, textRange: TextRange) {
4513    if (menuItem.id.equals(TextMenuItemId.of('extension1'))) {
4514      console.log('click' + menuItem.content + ', textRange=' + JSON.stringify(textRange))
4515      return true;
4516    }
4517    return false;
4518  }
4519
4520  build() {
4521    Row() {
4522      RichEditor(this.options)
4523        .onReady(() => {
4524          this.controller.addTextSpan("Extended RichEditor")
4525        })
4526        .editMenuOptions({
4527          onCreateMenu: (menuItems: Array<TextMenuItem>) => {
4528            return this.onCreateMenu(menuItems)
4529          },
4530          onMenuItemClick: (menuItem: TextMenuItem, textRange: TextRange) => {
4531            return this.onMenuItemClicked(menuItem, textRange)
4532          }
4533        })
4534        .height(200)
4535        .borderWidth(1)
4536        .borderColor(Color.Red)
4537    }
4538  }
4539}
4540```
4541
4542![RichEditorSelectionMenuOptions](figures/richEditorSelectionMenuOptions.png)
4543
4544<!--no_check-->