• 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>  Drag effects such as floating for the **\<RichEditor>** component can only be implemented through the [onDragStart](ts-universal-events-drag-drop.md) event.
10
11
12## Child Components
13
14This component can contain the [\<Span>](ts-basic-components-span.md) and [\<ImageSpan>](ts-basic-components-imagespan.md) child components.
15
16
17## APIs
18
19RichEditor(value: RichEditorOptions)
20
21**Parameters**
22
23| Name| Type| Mandatory| Description|
24| -------- | -------- | -------- | -------- |
25| value | [RichEditorOptions](#richeditoroptions)  | Yes| Options for initializing the component.|
26
27
28## Attributes
29
30The [universal attributes](ts-universal-attributes-size.md) are supported.
31
32>  **NOTE**
33>
34>  The default value of the **clip** attribute is **true**.
35>
36>  The **align** attribute supports only the start, center, and end options.
37
38| Name                     | Type                                                    | Description                                                        |
39| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
40| customKeyboard | [CustomBuilder](ts-types.md#custombuilder8) | Custom keyboard.<br>**NOTE**<br>When a custom keyboard is set, activating the text box opens the specified custom component, instead of the system input method.<br>The 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.<br>The custom keyboard is displayed on top of the current page, without compressing or raising the page.<br>The custom keyboard cannot obtain the focus, but it blocks gesture events.<br>By default, the custom keyboard is closed when the input component loses the focus.|
41| copyOptions | [CopyOptions](ts-appendix-enums.md#copyoptions9) | Whether copy and paste is allowed for text content.<br>Default value: **CopyOptions.LocalDevice**<br>**NOTE**<br>If **copyOptions** is set to **CopyOptions.InApp** or **CopyOptions.LocalDevice**, long pressing content in the component will display a shortcut menu, after which you can adjust the content selection scope and perform the desired operation, such as copy and select all.<br>If **copyOptions** is set to **CopyOptions.None**, copy and paste is not allowed. |
42## Events
43
44In addition to the [universal events](ts-universal-events-click.md), the following events are supported.
45
46| Name                                                        | Description                                                    |
47| ------------------------------------------------------------ | ------------------------------------------------------------ |
48| onReady(callback: () =&gt; void) | Triggered when initialization of the component is completed.|
49| onSelect(callback: (value: [RichEditorSelection](#richeditorselection)) =&gt; void) | Triggered when selection (by clicking the left mouse button, highlighting the text to select, and releasing the left mouse button) is performed.<br>- **value**: information about all selected spans.|
50| aboutToIMEInput(callback: (value: [RichEditorInsertValue](#richeditorinsertvalue)) =&gt; boolean) | Triggered when content is about to be entered in the input method.<br>- **value**: content to be entered in the input method.|
51| onIMEInputComplete(callback: (value: [RichEditorTextSpanResult](#richeditortextspanresult)) =&gt; void) | Triggered when text input is completed.<br>- **value**: text span information after text input is completed.|
52| aboutToDelete(callback: (value: [RichEditorDeleteValue](#richeditordeletevalue)) =&gt; boolean) | Triggered when content is about to be deleted in the input method.<br>- **value**: information about the text span where the content to be deleted is located.|
53| onDeleteComplete(callback: () =&gt; void) | Triggered when deletion in the input method is completed.|
54
55## RichEditorInsertValue
56
57Describes the text to be inserted.
58
59| Name| Type| Mandatory| Description|
60| -------- | -------- | -------- | -------- |
61| insertOffset | number  | Yes| Offset of the text to be inserted.|
62| insertValue | string  | Yes| Content of the text to be inserted.|
63
64
65## RichEditorDeleteValue
66
67| Name| Type| Mandatory| Description|
68| -------- | -------- | -------- | -------- |
69| offset | number  | Yes| Offset of the text to be deleted.|
70| direction | [RichEditorDeleteDirection](#richeditordeletedirection)  | Yes| Direction of the delete operation.|
71| length | number | Yes| Length of the content to be deleted.|
72| richEditorDeleteSpans | Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes| Information about the text or image spans to be deleted.|
73
74
75## RichEditorDeleteDirection
76
77Enumerates the directions of the delete operation.
78
79| Name   | Description                         |
80| -------- | ------------------------------ |
81| BACKWARD      | Backward. |
82| FORWARD   | Forward.     |
83
84
85## RichEditorTextSpanResult
86
87Provides the text span information.
88
89| Name| Type| Mandatory| Description|
90| -------- | -------- | -------- | -------- |
91| spanPosition | [RichEditorSpanPosition](#richeditorspanposition)  | Yes| Span position.|
92| value | string | Yes| Text span content.|
93| textStyle | [RichEditorTextStyleResult](#richeditortextstyleresult) | Yes| Text span style.|
94| offsetInSpan | [number, number] | Yes| Start and end positions of the valid content in the text span.|
95
96
97## RichEditorSpanPosition
98
99Provides the span position information.
100
101| Name| Type| Mandatory| Description|
102| -------- | -------- | -------- | -------- |
103| spanIndex | number  | Yes| Span index.|
104| spanRange | [number, number]  | Yes| Start and end positions of the span content in the **\<RichEditor>** component.|
105
106
107## RichEditorTextStyleResult
108
109Provides the text span style information returned by the backend.
110
111| Name| Type| Mandatory| Description                              |
112| ------ | -------- | ---- | -------------------------------------- |
113| fontColor | [ResourceColor](ts-types.md#resourcecolor) | Yes| Font color.|
114| fontSize |  number   | Yes| Font size.|
115| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | Yes| Font style.|
116| fontWeight |  number | Yes| Font weight.|
117| fontFamily  |  string | Yes| Font family.|
118| decoration | {<br>type: [TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br>color: [ResourceColor](ts-types.md#resourcecolor)<br>} | Yes   | Style and color of the text decorative line.|
119
120
121## RichEditorImageSpanResult
122
123Provides the image information returned by the backend.
124
125| Name              | Type                                                               | Mandatory | Description              |
126|------------------|-------------------------------------------------------------------|-----|------------------|
127| spanPosition     | [RichEditorSpanPosition](#richeditorspanposition)                 | Yes  | Span position.         |
128| valuePixelMap    | [PixelMap](../apis/js-apis-image.md#pixelmap7)                    | No  | Image content.           |
129| valueResourceStr | [ResourceStr](ts-types.md#resourcestr)                            | No  | Image resource ID.         |
130| imageStyle       | [RichEditorImageSpanStyleResult](#richeditorimagespanstyleresult) | Yes  | Image style.           |
131| offsetInSpan     | [number, number]                                                  | Yes  | Start and end positions of the image in the span.|
132
133## RichEditorImageSpanStyleResult
134
135Provides the image span style information returned by the backend.
136
137| Name| Type| Mandatory| Description                              |
138| ------ | -------- | ---- | -------------------------------------- |
139| size | [number, number] | Yes| Width and height of the image.|
140| verticalAlign  | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | Yes | Vertical alignment mode of the image.|
141| objectFit  | [ImageFit](ts-appendix-enums.md#imagefit) | Yes| Scale mode of the image.|
142
143
144## RichEditorOptions
145
146Defines the options for initializing the **\<RichEditor>** component.
147
148| Name| Type| Mandatory| Description|
149| -------- | -------- | -------- | -------- |
150| controller | [RichEditorController](#richeditorcontroller)  | Yes| Controller for the **\<RichEditor>** component.|
151
152
153## RichEditorController
154
155Implements the controller for the **\<RichEditor>** component.
156
157### Objects to Import
158
159```
160controller: RichEditorController = new RichEditorController()
161```
162
163### getCaretOffset
164
165getCaretOffset(): number
166
167Obtains the current cursor position.
168
169**Return value**
170
171| Type                     | Description              |
172| ----------------------- | ---------------- |
173| number | Cursor position.|
174
175### setCaretOffset
176
177setCaretOffset(offset: number): boolean
178
179Sets the cursor position.
180
181**Parameters**
182
183| Name| Type| Mandatory| Description                              |
184| ------ | -------- | ---- | -------------------------------------- |
185| offset | number | Yes| Offset of the cursor. If the value is out of the text range, the setting fails.|
186
187**Return value**
188
189| Type                     | Description              |
190| ----------------------- | ---------------- |
191| boolean | Whether the cursor position is set successfully.|
192
193### addTextSpan
194
195addTextSpan(value: string, options?: RichEditorTextSpanOptions): number
196
197Adds a text span.
198
199**Parameters**
200
201| Name| Type| Mandatory| Description                              |
202| ------ | -------- | ---- | -------------------------------------- |
203| value  | string   | Yes  | Text content.|
204| options  | [RichEditorTextSpanOptions](#richeditortextspanoptions)   | No  | Text options.|
205
206**Return value**
207
208| Type                     | Description              |
209| ----------------------- | ---------------- |
210| number | Position of the added text span.|
211
212### addImageSpan
213
214addImageSpan(value: PixelMap | ResourceStr, options?: RichEditorImageSpanOptions): number
215
216Adds an image span.
217
218**Parameters**
219
220| Name| Type| Mandatory| Description                              |
221| ------ | -------- | ---- | -------------------------------------- |
222| value  | [PixelMap](../apis/js-apis-image.md#pixelmap7)\|[ResourceStr](ts-types.md#resourcestr)   | Yes  | Image content.|
223| options  | [RichEditorImageSpanOptions](#richeditorimagespanoptions)   | No  | Image options.|
224
225**Return value**
226
227| Type                     | Description              |
228| ----------------------- | ---------------- |
229| number | Position of the added image span.|
230
231
232### updateSpanStyle
233
234updateSpanStyle(value: RichEditorUpdateTextSpanStyleOptions | RichEditorUpdateImageSpanStyleOptions): void
235
236Updates the text or image 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.
237
238**Parameters**
239
240| Name| Type| Mandatory| Description                              |
241| ------ | -------- | ---- | -------------------------------------- |
242| value | [RichEditorUpdateTextSpanStyleOptions](#richeditorupdatetextspanstyleoptions) \| [RichEditorUpdateImageSpanStyleOptions](#richeditorupdateimagespanstyleoptions) | Yes| Text or image span style options.|
243
244
245### getSpans
246
247getSpans(value?: RichEditorRange): Array<RichEditorTextSpanResult| RichEditorImageSpanResult>
248
249Obtains span information.
250
251**Parameters**
252
253| Name| Type                           | Mandatory| Description        |
254| ------ | ----------------------------------- | ---- | ---------------- |
255| value  | [RichEditorRange](#richeditorrange) | No  | Range of the target span.|
256
257**Return value**
258
259| Type                     | Description              |
260| ----------------------- | ---------------- |
261| Array<[RichEditorTextSpanResult](#richeditortextspanresult) \| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Text and image span information.|
262
263### deleteSpans
264
265deleteSpans(value?: RichEditorRange): void
266
267Deletes the text and image spans in a specified range.
268
269**Parameters**
270
271| Name| Type| Mandatory| Description                              |
272| ------ | -------- | ---- | -------------------------------------- |
273| value | [RichEditorRange](#richeditorrange) | No| Range of the target spans. If this parameter is omitted, all text and image spans will be deleted.|
274
275
276## RichEditorSelection
277
278Provides information about the selected content.
279
280| Name     | Type                                                        | Mandatory| Description      |
281| --------- | ------------------------------------------------------------ | ---- | ---------- |
282| selection | [number, number]                                             | Yes  | Range of the selected.|
283| spans     | Array<[RichEditorTextSpanResult](#richeditortextspanresult)\| [RichEditorImageSpanResult](#richeditorimagespanresult)> | Yes  | Span information.  |
284
285
286## RichEditorUpdateTextSpanStyleOptions
287
288Defines the text span style options.
289
290| Name       | Type                                      | Mandatory  | Description                             |
291| --------- | ---------------------------------------- | ---- | ------------------------------- |
292| 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. |
293| 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.|
294| textStyle | [RichEditorTextStyle](#richeditortextstyle) | Yes   | Text style.                          |
295
296
297## RichEditorUpdateImageSpanStyleOptions
298
299Defines the image span style options.
300
301| Name        | Type                                      | Mandatory  | Description                             |
302| ---------- | ---------------------------------------- | ---- | ------------------------------- |
303| 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. |
304| 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.|
305| imageStyle | [RichEditorImageSpanStyle](#richeditorimagespanstyle) | Yes   | Image style.                          |
306
307
308## RichEditorTextSpanOptions
309
310Describes the options for adding a text span.
311
312| Name| Type| Mandatory| Description                              |
313| ------ | -------- | ---- | -------------------------------------- |
314| offset  | number   | No  | Position of the text span to be added. If this parameter is omitted, the text span will be added to the end of all text strings.|
315| style  | [RichEditorTextStyle](#richeditortextstyle)   | No  | Style of the text span to be added. If this parameter is omitted, the default text style will be used.|
316
317## RichEditorTextStyle
318
319Provides the text style information.
320
321| Name| Type| Mandatory| Description                              |
322| ------ | -------- | ---- | -------------------------------------- |
323| fontColor | [ResourceColor](ts-types.md#resourcecolor) | No| Font color.<br> Default value: **Color.Black**|
324| 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.<br>Since API version 9, this API is supported in ArkTS widgets.|
325| fontStyle | [FontStyle](ts-appendix-enums.md#fontstyle) | No| Font style.<br>Default value: **FontStyle.Normal**|
326| 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**|
327| fontFamily  | [ResourceStr](ts-types.md#resourcestr) | No| Font family. The HarmonyOS Sans font and [register custom fonts](../apis/js-apis-font.md) are supported.<br>Default font: **'HarmonyOS Sans'**|
328| decoration  | {<br>type: [TextDecorationType](ts-appendix-enums.md#textdecorationtype),<br>color?: [ResourceColor](ts-types.md#resourcecolor)<br>} | No| Style and color of the text decorative line.<br>Default value: {<br>type: TextDecorationType.None,<br>color: Color.Black<br>}|
329
330
331## RichEditorImageSpanOptions
332
333Defines the options for adding an image span.
334
335| Name| Type| Mandatory| Description                              |
336| ------ | -------- | ---- | -------------------------------------- |
337| offset  | number   | No  | Position of the image span to be added. If this parameter is omitted, the image span will be added to the end of all text strings.|
338| imageStyle  | [RichEditorImageSpanStyle](#richeditorimagespanstyle)   | No  | Image style. If this parameter is omitted, the default image style will be used.|
339
340## RichEditorImageSpanStyle
341
342Provides the image span style information.
343
344| Name| Type| Mandatory| Description                              |
345| ------ | -------- | ---- | -------------------------------------- |
346| size  | [[Dimension](ts-types.md#dimension10), [Dimension](ts-types.md#dimension10)]  | No| Width and height of the image.|
347| verticalAlign  | [ImageSpanAlignment](ts-basic-components-imagespan.md#imagespanalignment) | No  | Vertical alignment mode of the image.<br>Default value: **ImageSpanAlignment.BASELINE**|
348| objectFit  | [ImageFit](ts-appendix-enums.md#imagefit) | No| Scale mode of the image.<br> Default value: **ImageFit.Cover**|
349
350## RichEditorRange
351
352Provides the span range information.
353
354| Name   | Type    | Mandatory  | Description                    |
355| ----- | ------ | ---- | ---------------------- |
356| start | number | No   | Start position. If this parameter is left empty or set to a negative value, the value **0** will be used. |
357| 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.|
358
359
360## Example
361
362### Example 1
363
364```ts
365// xxx.ets
366@Entry
367@Component
368struct Index {
369  controller: RichEditorController = new RichEditorController()
370  options: RichEditorOptions = { controller: this.controller }
371  private start: number = -1
372  private end: number = -1
373  @State message: string = "[-1, -1]"
374  @State content: string = ""
375
376  build() {
377    Column() {
378      Column() {
379        Text("selection range:").width("100%")
380        Text() {
381          Span(this.message)
382        }.width("100%")
383        Text("selection content:").width("100%")
384        Text() {
385          Span(this.content)
386        }.width("100%")
387      }
388      .borderWidth(1)
389      .borderColor(Color.Red)
390      .width("100%")
391      .height("20%")
392
393      Row() {
394        Button ("Update Style: Bold").onClick(() => {
395          this.controller.updateSpanStyle({
396            start: this.start,
397            end: this.end,
398            textStyle:
399            {
400              fontWeight: FontWeight.Bolder
401            }
402          })
403        })
404        Button("Obtain Selection").onClick(() => {
405          this.content = "";
406          this.controller.getSpans({
407            start: this.start,
408            end: this.end
409          }).forEach(item => {
410            if(typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined'){
411              this.content += (item as RichEditorImageSpanResult).valueResourceStr
412              this.content += "\n"
413            } else {
414              this.content += (item as RichEditorTextSpanResult).value
415              this.content += "\n"
416            }
417          })
418        })
419        Button("Delete Selection").onClick(() => {
420          this.controller.deleteSpans({
421            start: this.start,
422            end: this.end
423          })
424          this.start = -1
425          this.end = -1
426          this.message = "[" + this.start + ", " + this.end + "]"
427        })
428      }
429      .borderWidth(1)
430      .borderColor(Color.Red)
431      .width("100%")
432      .height("10%")
433
434      Column() {
435        RichEditor(this.options)
436          .onReady(() => {
437            this.controller.addTextSpan("0123456789",
438              {
439                style:
440                {
441                  fontColor: Color.Orange,
442                  fontSize: 30
443                }
444              })
445            this.controller.addImageSpan($r("app.media.icon"),
446              {
447                imageStyle:
448                {
449                  size: ["57px", "57px"]
450                }
451              })
452            this.controller.addTextSpan("0123456789",
453              {
454                style:
455                {
456                  fontColor: Color.Black,
457                  fontSize: 30
458                }
459              })
460          })
461          .onSelect((value: RichEditorSelection) => {
462            this.start = value.selection[0]
463            this.end = value.selection[1]
464            this.message = "[" + this.start + ", " + this.end + "]"
465          })
466          .aboutToIMEInput((value: RichEditorInsertValue) => {
467            console.log("---------------------- aboutToIMEInput ----------------------")
468            console.log("insertOffset:" + value.insertOffset)
469            console.log("insertValue:" + value.insertValue)
470            return true
471          })
472          .onIMEInputComplete((value: RichEditorTextSpanResult) => {
473            console.log("---------------------- onIMEInputComplete ---------------------")
474            console.log("spanIndex:" + value.spanPosition.spanIndex)
475            console.log("spanRange:[" + value.spanPosition.spanRange[0] + "," + value.spanPosition.spanRange[1] + "]")
476            console.log("offsetInSpan:[" + value.offsetInSpan[0] + "," + value.offsetInSpan[1] + "]")
477            console.log("value:" + value.value)
478          })
479          .aboutToDelete((value: RichEditorDeleteValue) => {
480            console.log("---------------------- aboutToDelete --------------------------")
481            console.log("offset:" + value.offset)
482            console.log("direction:" + value.direction)
483            console.log("length:" + value.length)
484            value.richEditorDeleteSpans.forEach(item => {
485              console.log("---------------------- item --------------------------")
486              console.log("spanIndex:" + item.spanPosition.spanIndex)
487              console.log("spanRange:[" + item.spanPosition.spanRange[0] + "," + item.spanPosition.spanRange[1] + "]")
488              console.log("offsetInSpan:[" + item.offsetInSpan[0] + "," + item.offsetInSpan[1] + "]")
489              if (typeof(item as RichEditorImageSpanResult)['imageStyle'] != 'undefined') {
490                console.log("image:" + (item as RichEditorImageSpanResult).valueResourceStr)
491              } else {
492                console.log("text:" + (item as RichEditorTextSpanResult).value)
493              }
494            })
495            return true
496          })
497          .onDeleteComplete(() => {
498            console.log("---------------------- onDeleteComplete ------------------------")
499          })
500          .borderWidth(1)
501          .borderColor(Color.Green)
502          .width("100%")
503          .height("30%")
504      }
505      .borderWidth(1)
506      .borderColor(Color.Red)
507      .width("100%")
508      .height("70%")
509    }
510  }
511}
512```
513![richeditor](figures/richeditor.gif)
514
515### Example 2
516
517```ts
518// xxx.ets
519@Entry
520@Component
521struct RichEditorExample {
522  controller: RichEditorController = new RichEditorController()
523
524  // Create a custom keyboard component.
525  @Builder CustomKeyboardBuilder() {
526    Column() {
527      Grid() {
528        ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, '*', 0, '#'], (item: number | string) => {
529          GridItem() {
530            Button(item + "")
531              .width(110).onClick(() => {
532              this.controller.addTextSpan(item + '', {
533                offset: this.controller.getCaretOffset(),
534                style:
535                {
536                  fontColor: Color.Orange,
537                  fontSize: 30
538                }
539              })
540              this.controller.setCaretOffset(this.controller.getCaretOffset() + item.toString().length)
541            })
542          }
543        })
544      }.maxCount(3).columnsGap(10).rowsGap(10).padding(5)
545    }.backgroundColor(Color.Gray)
546  }
547
548  build() {
549    Column() {
550      RichEditor({ controller: this.controller })
551        // Bind the custom keyboard.
552        .customKeyboard(this.CustomKeyboardBuilder()).margin(10).border({ width: 1 })
553        .height(200)
554        .borderWidth(1)
555        .borderColor(Color.Red)
556        .width("100%")
557    }
558  }
559}
560```
561
562![customKeyboard](figures/richEditorCustomKeyboard.gif)
563