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