# SelectionMenu The **SelectionMenu** component serves as a context menu designed specifically for text selection in the [RichEditor](ts-basic-components-richeditor.md) or [Text](ts-basic-components-text.md) component. This component must be bound to either a **RichEditor** component through its [bindSelectionMenu](ts-basic-components-richeditor.md#bindselectionmenu) API or a **Text** component using its [bindSelectionMenu](ts-basic-components-text.md#bindselectionmenu11) API to work properly, as it cannot operate as an independent UI element. It is recommended that this component be displayed through mouse right-click or text selection events. > **NOTE** > > This component is supported since API version 11. Updates will be marked with a superscript to indicate their earliest API version. > > This component is not supported on wearables. ## Modules to Import ```ts import { SelectionMenu, EditorMenuOptions, ExpandedMenuOptions, EditorEventInfo, SelectionMenuOptions } from '@kit.ArkUI'; ``` ## Child Components Not supported ## SelectionMenu SelectionMenu(options: SelectionMenuOptions): void Defines a **SelectionMenu** component. When the input parameter is empty, the sizes of the component and its content area are 0, making the component invisible. In this case, for example, if the **SelectionMenu** component activated through right clicks is bound to a **RichEditor** component, it will not be displayed when the **RichEditor** component is right-clicked. **Decorator**: @Builder **Atomic service API**: This API can be used in atomic services since API version 12. **System capability**: SystemCapability.ArkUI.ArkUI.Full **Parameters** | Name| Type| Mandatory| Description| | -------- | -------- | -------- | -------- | | options | [SelectionMenuOptions](#selectionmenuoptions) | Yes| Configuration options of the **SelectionMenu** component.| ## SelectionMenuOptions Defines the configuration options of the **SelectionMenu** component. **Atomic service API**: This API can be used in atomic services since API version 12. **System capability**: SystemCapability.ArkUI.ArkUI.Full | Name| Type| Mandatory| Description| | -------- | -------- | -------- | -------- | | editorMenuOptions | Array<[EditorMenuOptions](#editormenuoptions)> | No| Edit menu.
If **editorMenuOptions** is not set, the edit menu is not displayed.
When both **action** and **builder** in **EditorMenuOptions** are configured, clicking the edit icon will trigger both.
By default, the context menu is not closed when the edit menu icon is clicked. You can configure **closeSelectionMenu** of **RichEditorController** in **action** to enable the menu to be closed.| | expandedMenuOptions | Array<[ExpandedMenuOptions](#expandedmenuoptions)> | No| Expanded drop-down menu options.
If this parameter is left empty, the expanded drop-down menu is not displayed.
The options configured for **ExpandedMenuOptions** are displayed in the **More** menu option, and clicking **More** shows the expanded drop-down menu.| | controller | [RichEditorController](ts-basic-components-richeditor.md#richeditorcontroller) | No| Rich text editor controller. If **controller** is set, the default system menu (including the cut, copy, and paste options) is displayed, and the preset menu features are provided.
If **controller** is left empty, the **More** menu option is not displayed. If **expandedMenuOptions** is not empty, the expanded drop-down menu is displayed.
By default, the copy and paste feature is only available for rich text. To use the feature for content that includes both text and images, define custom **onCopy** and **onPaste** APIs. If a custom **onCopy** \| **onPaste** API is defined, the default copy and paste feature is ineffective, and the custom API is called instead.
**NOTE**
When the preset copy option is selected, the custom context menu on selection is hidden, while the selected text is still highlighted.
When the preset select-all option is selected, the custom context menu on selection is hidden, while all text is highlighted.
When the preset paste option is selected, the style of the copied text is retained, whether the text is pasted to a blank area or not.
When the **copyOptions** attribute of the [RichEditor](ts-basic-components-richeditor.md) component is set to **CopyOptions.None**, the preset copy and cut features are not restricted.| | onCopy | (event?: [EditorEventInfo](#editoreventinfo)) => void | No| Event callback to take the place of the preset copy menu option.
It is effective only when the **controller** parameter is set and the preset menu is available.
**NOTE**
**event** indicates the returned information.| | onPaste | (event?: [EditorEventInfo](#editoreventinfo)) => void | No| Event callback to take the place of the preset paste menu option.
It is effective only when the **controller** parameter is set and the preset menu is available.
**NOTE**
**event** indicates the returned information.| | onCut | (event?: [EditorEventInfo](#editoreventinfo)) => void | No| Event callback to take the place of the preset cut menu option.
It is effective only when the **controller** parameter is set and the preset menu is available.
**NOTE**
**event** indicates the returned information.| | onSelectAll | (event?: [EditorEventInfo](#editoreventinfo)) => void | No| Event callback to take the place of the preset select-all menu option.
It is effective only when the **controller** parameter is set and the preset menu is available.
**NOTE**
**event** indicates the returned information.| ## EditorMenuOptions Describes the edit menu options. **System capability**: SystemCapability.ArkUI.ArkUI.Full | Name| Type| Mandatory| Description| | -------- | -------- | -------- | -------- | | icon | [ResourceStr](ts-types.md#resourcestr) | Yes| Icon.
**Atomic service API**: This API can be used in atomic services since API version 12.| | builder | () => void | No| Builder of the custom component displayed upon click. It must be used with @Builder for building the custom component.
**Atomic service API**: This API can be used in atomic services since API version 12.| | action | () => void | No| Action triggered when the menu option is clicked.
**Atomic service API**: This API can be used in atomic services since API version 12.| | symbolStyle18+ | [SymbolGlyphModifier](ts-universal-attributes-attribute-modifier.md) | No| Symbol icon resource, which has higher priority than **icon**.
**Atomic service API**: This API can be used in atomic services since API version 18.| ## ExpandedMenuOptions Describes the expanded drop-down menu options. Inherits from [MenuItemOptions](ts-basic-components-menuitem.md#menuitemoptions). **Atomic service API**: This API can be used in atomic services since API version 12. **System capability**: SystemCapability.ArkUI.ArkUI.Full | Name| Type| Mandatory| Description| | -------- | -------- | -------- | -------- | | action | () => void | No| Action triggered when the menu option is clicked.| ## EditorEventInfo Provides the information about the selected content. **Atomic service API**: This API can be used in atomic services since API version 12. **System capability**: SystemCapability.ArkUI.ArkUI.Full | Name| Type| Mandatory| Description| | -------- | -------- | -------- | -------- | | content | [RichEditorSelection](ts-basic-components-richeditor.md#richeditorselection) | No| Information about the selected content.| ## Attributes The [universal attributes](ts-component-general-attributes.md) are not supported. The default width is 224 vp, and the height is adaptive. ## Events The [universal events](ts-component-general-events.md) are not supported. ## Example ### Example 1: Binding Context Menus on Selection with Different Trigger Methods This example demonstrates the effects of a custom context menu on selection bound to text with different triggering modes. ```ts import { SelectionMenu, EditorMenuOptions, ExpandedMenuOptions, EditorEventInfo, SelectionMenuOptions } from '@kit.ArkUI'; @Entry @Component struct Index { @State select: boolean = true; controller: RichEditorController = new RichEditorController(); options: RichEditorOptions = { controller: this.controller }; @State message: string = 'Hello world'; @State textSize: number = 30; @State fontWeight: FontWeight = FontWeight.Normal; @State start: number = -1; @State end: number = -1; @State visibleValue: Visibility = Visibility.Visible; @State colorTransparent: Color = Color.Transparent; @State textStyle: RichEditorTextStyle = {}; private editorMenuOptions: Array = [ { icon: $r("app.media.ic_notepad_textbold"), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.fontWeight != 11) { this.textStyle.fontWeight = FontWeight.Bolder; } else { this.textStyle.fontWeight = FontWeight.Normal; } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }, { icon: $r("app.media.ic_notepad_texttilt"), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.fontStyle == FontStyle.Italic) { this.textStyle.fontStyle = FontStyle.Normal; } else { this.textStyle.fontStyle = FontStyle.Italic; } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }, { icon: $r("app.media.ic_notepad_underline"), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.decoration) { if (this.textStyle.decoration.type == TextDecorationType.Underline) { this.textStyle.decoration.type = TextDecorationType.None; } else { this.textStyle.decoration.type = TextDecorationType.Underline; } } else { this.textStyle.decoration = { type: TextDecorationType.Underline, color: Color.Black } } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }, { icon: $r("app.media.ic_notepad_fontsize"), action: () => { }, builder: (): void => this.sliderPanel() }, { icon: $r("app.media.ic_notepad_textcolor"), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.fontColor == Color.Orange || this.textStyle.fontColor == '#FFFFA500') { this.textStyle.fontColor = Color.Black; } else { this.textStyle.fontColor = Color.Orange; } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }] private expandedMenuOptions: Array = [{ startIcon: $r("app.media.startIcon"), content: 'Dictionary', action: () => { } }, { startIcon: $r("app.media.startIcon"), content: 'Translate', action: () => { } }, { startIcon: $r("app.media.startIcon"), content: 'Search', action: () => { } }] private expandedMenuOptions1: Array = [] private editorMenuOptions1: Array = [] private selectionMenuOptions: SelectionMenuOptions = { editorMenuOptions: this.editorMenuOptions, expandedMenuOptions: this.expandedMenuOptions, controller: this.controller, onCut: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test cut' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } }, onPaste: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test onPaste' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } }, onCopy: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test cut' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } }, onSelectAll: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test onPaste' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } } } @Builder sliderPanel() { Column() { Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { Text('A').fontSize(15) Slider({ value: this.textSize, step: 10, style: SliderStyle.InSet }) .width(210) .onChange((value: number, mode: SliderChangeMode) => { if (this.controller) { let selection = this.controller.getSelection(); if (mode == SliderChangeMode.End) { if (this.textSize == undefined) { this.textSize = 0; } let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { this.textSize = Math.max(this.textSize, (item as RichEditorTextSpanResult).textStyle.fontSize); } }) } if (mode == SliderChangeMode.Moving || mode == SliderChangeMode.Click) { this.start = selection.selection[0]; this.end = selection.selection[1]; this.textSize = value; this.controller.updateSpanStyle({ start: this.start, end: this.end, textStyle: { fontSize: this.textSize } }) } } }) Text('A').fontSize(20).fontWeight(FontWeight.Medium) }.borderRadius($r('sys.float.ohos_id_corner_radius_card')) } .shadow(ShadowStyle.OUTER_DEFAULT_MD) .backgroundColor(Color.White) .borderRadius($r('sys.float.ohos_id_corner_radius_card')) .padding(15) .height(48) } @Builder MyMenu() { Column() { SelectionMenu(this.selectionMenuOptions) } .width(256) .backgroundColor(Color.Transparent) } @Builder MyMenu2() { Column() { SelectionMenu({ editorMenuOptions: this.editorMenuOptions, expandedMenuOptions: this.expandedMenuOptions1, controller: this.controller, }) } .width(256) .backgroundColor(Color.Transparent) } @Builder MyMenu3() { Column() { SelectionMenu({ editorMenuOptions: this.editorMenuOptions, expandedMenuOptions: this.expandedMenuOptions, controller: this.controller, }) } .width(256) .backgroundColor(Color.Transparent) } build() { Column() { Button("SetSelection") .onClick((event: ClickEvent) => { if (this.controller) { this.controller.setSelection(0, 2); } }) RichEditor(this.options) .onReady(() => { this.controller.addTextSpan(this.message, { style: { fontColor: Color.Orange, fontSize: 30 } }); this.controller.addTextSpan(this.message, { style: { fontColor: Color.Black, fontSize: 25 } }); }) .onSelect((value: RichEditorSelection) => { if (value.selection[0] == -1 && value.selection[1] == -1) { return; } this.start = value.selection[0]; this.end = value.selection[1]; }) .bindSelectionMenu(RichEditorSpanType.TEXT, this.MyMenu3(), RichEditorResponseType.RIGHT_CLICK) .bindSelectionMenu(RichEditorSpanType.TEXT, this.MyMenu2(), RichEditorResponseType.SELECT) .borderWidth(1) .borderColor(Color.Red) .width(200) .height(200) .margin(10) } } } ``` > **NOTE** > > 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 **editorMenuOptions** with the desired icons. ![selectionmenu](figures/selectionmenu.gif) ### Example 2: Setting the Symbol Icon This example demonstrates how to use **symbolStyle** in **EditorMenuOptions** to set custom symbol icons. ```ts import { SelectionMenu, EditorMenuOptions, ExpandedMenuOptions, EditorEventInfo, SelectionMenuOptions, SymbolGlyphModifier } from '@kit.ArkUI' @Entry @Component struct Index { @State select: boolean = true; controller: RichEditorController = new RichEditorController(); options: RichEditorOptions = { controller: this.controller }; @State message: string = 'Hello world'; @State textSize: number = 30; @State fontWeight: FontWeight = FontWeight.Normal; @State start: number = -1; @State end: number = -1; @State visibleValue: Visibility = Visibility.Visible; @State colorTransparent: Color = Color.Transparent; @State textStyle: RichEditorTextStyle = {}; private editorMenuOptions: Array = [ { icon: $r("sys.media.wifi_router_fill"), symbolStyle: new SymbolGlyphModifier($r('sys.symbol.save')), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.fontWeight != 11) { this.textStyle.fontWeight = FontWeight.Bolder; } else { this.textStyle.fontWeight = FontWeight.Normal; } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }, { icon: $r("sys.media.save_button_picture"), symbolStyle: new SymbolGlyphModifier($r('sys.symbol.camera')), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.fontStyle == FontStyle.Italic) { this.textStyle.fontStyle = FontStyle.Normal; } else { this.textStyle.fontStyle = FontStyle.Italic; } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }, { icon: $r("sys.media.waveform_folder_fill"), symbolStyle: new SymbolGlyphModifier($r('sys.symbol.car')), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.decoration) { if (this.textStyle.decoration.type == TextDecorationType.Underline) { this.textStyle.decoration.type = TextDecorationType.None; } else { this.textStyle.decoration.type = TextDecorationType.Underline; } } else { this.textStyle.decoration = { type: TextDecorationType.Underline, color: Color.Black } } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }, { icon: $r("app.media.app_icon"), action: () => { }, builder: (): void => this.sliderPanel() }, { icon: $r("sys.media.thermometer_fill"), action: () => { if (this.controller) { let selection = this.controller.getSelection(); let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; this.textStyle = span.textStyle; let start = span.offsetInSpan[0]; let end = span.offsetInSpan[1]; let offset = span.spanPosition.spanRange[0]; if (this.textStyle.fontColor == Color.Orange || this.textStyle.fontColor == '#FFFFA500') { this.textStyle.fontColor = Color.Black; } else { this.textStyle.fontColor = Color.Orange; } this.controller.updateSpanStyle({ start: offset + start, end: offset + end, textStyle: this.textStyle }) } }) } } }] private expandedMenuOptions: Array = [{ startIcon: $r("app.media.startIcon"), content: 'Dictionary', action: () => { } }, { startIcon: $r("app.media.startIcon"), content: 'Translate', action: () => { } }, { startIcon: $r("app.media.startIcon"), content: 'Search', action: () => { } }] private expandedMenuOptions1: Array = [] private editorMenuOptions1: Array = [] private selectionMenuOptions: SelectionMenuOptions = { editorMenuOptions: this.editorMenuOptions, expandedMenuOptions: this.expandedMenuOptions, controller: this.controller, onCut: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test cut' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } }, onPaste: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test onPaste' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } }, onCopy: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test cut' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } }, onSelectAll: (event?: EditorEventInfo) => { if (event && event.content) { event.content.spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { let span = item as RichEditorTextSpanResult; console.info('test onPaste' + span.value); console.info('test start ' + span.offsetInSpan[0] + ' end: ' + span.offsetInSpan[1]); } }) } } } @Builder sliderPanel() { Column() { Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) { Text('A').fontSize(15) Slider({ value: this.textSize, step: 10, style: SliderStyle.InSet }) .width(210) .onChange((value: number, mode: SliderChangeMode) => { if (this.controller) { let selection = this.controller.getSelection(); if (mode == SliderChangeMode.End) { if (this.textSize == undefined) { this.textSize = 0; } let spans = selection.spans; spans.forEach((item: RichEditorTextSpanResult | RichEditorImageSpanResult, index) => { if (typeof (item as RichEditorTextSpanResult)['textStyle'] != 'undefined') { this.textSize = Math.max(this.textSize, (item as RichEditorTextSpanResult).textStyle.fontSize); } }) } if (mode == SliderChangeMode.Moving || mode == SliderChangeMode.Click) { this.start = selection.selection[0]; this.end = selection.selection[1]; this.textSize = value; this.controller.updateSpanStyle({ start: this.start, end: this.end, textStyle: { fontSize: this.textSize } }) } } }) Text('A').fontSize(20).fontWeight(FontWeight.Medium) }.borderRadius($r('sys.float.ohos_id_corner_radius_card')) } .shadow(ShadowStyle.OUTER_DEFAULT_MD) .backgroundColor(Color.White) .borderRadius($r('sys.float.ohos_id_corner_radius_card')) .padding(15) .height(48) } @Builder MyMenu() { Column() { SelectionMenu(this.selectionMenuOptions) } .width(256) .backgroundColor(Color.Transparent) } @Builder MyMenu2() { Column() { SelectionMenu({ editorMenuOptions: this.editorMenuOptions, expandedMenuOptions: this.expandedMenuOptions1, controller: this.controller, }) } .width(256) .backgroundColor(Color.Transparent) } @Builder MyMenu3() { Column() { SelectionMenu({ editorMenuOptions: this.editorMenuOptions1, expandedMenuOptions: this.expandedMenuOptions, controller: this.controller, }) } .width(256) .backgroundColor(Color.Transparent) } build() { Column() { Button("SetSelection") .onClick((event: ClickEvent) => { if (this.controller) { this.controller.setSelection(0, 2); } }) RichEditor(this.options) .onReady(() => { this.controller.addTextSpan(this.message, { style: { fontColor: Color.Orange, fontSize: 30 } }); this.controller.addTextSpan(this.message, { style: { fontColor: Color.Black, fontSize: 25 } }); }) .onSelect((value: RichEditorSelection) => { if (value.selection[0] == -1 && value.selection[1] == -1) { return; } this.start = value.selection[0]; this.end = value.selection[1]; }) .bindSelectionMenu(RichEditorSpanType.TEXT, this.MyMenu3(), RichEditorResponseType.RIGHT_CLICK) .bindSelectionMenu(RichEditorSpanType.TEXT, this.MyMenu2(), RichEditorResponseType.SELECT) .borderWidth(1) .borderColor(Color.Red) .width(200) .height(200) } } } ``` ![selectionmenu02](figures/selectionmenu02.jpg)