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