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