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