1# Menu Control 2 3A context menu – a vertical list of items – can be bound to a component and displayed by long-pressing, clicking, or right-clicking the component. 4 5> **NOTE** 6> 7> - The APIs of this module are supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version. 8> 9> - **CustomBuilder** does not support the use of **bindMenu** and **bindContextMenu** methods. To display a multi-level menu, use the [\<Menu>](ts-basic-components-menu.md) component instead. 10> 11> - The text in the context menu cannot be selected by long-pressing. 12 13## bindMenu 14 15bindMenu(content: Array<MenuElement> | CustomBuilder, options?: MenuOptions) 16 17Menu bound to the component, which is displayed when the user clicks the component. A menu item can be a combination of text and icons or a custom component. 18 19**System capability**: SystemCapability.ArkUI.ArkUI.Full 20 21**Parameters** 22 23| Name | Type | Mandatory| Description | 24| ------- | ------------------------------------------------------------ | ---- | -------------------------------------------- | 25| content | Array<[MenuElement](#menuelement)> \| [CustomBuilder](ts-types.md#custombuilder8) | Yes | Array of menu item icons and text, or custom component.| 26| options | [MenuOptions](#menuoptions10) | No | Parameters of the context menu. | 27 28## bindMenu 29 30bindMenu(isShow: boolean, content: Array<MenuElement> | CustomBuilder, options?: MenuOptions) 31 32Menu bound to the component, which is displayed when the user clicks the component. A menu item can be a combination of text and icons or a custom component. 33 34**System capability**: SystemCapability.ArkUI.ArkUI.Full 35 36**Parameters** 37 38| Name | Type | Mandatory| Description | 39| -------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 40| isShow<sup>11+</sup> | boolean | Yes | Whether to show the menu. The default value is **false**. Menus can be displayed only after all pages are constructed. Therefore, this parameter cannot be set to **true** during page construction. Otherwise, display position and shape errors will occur. Two-way binding is not supported.| 41| content | Array<[MenuElement](#menuelement)> \| [CustomBuilder](ts-types.md#custombuilder8) | Yes | Array of menu item icons and text, or custom component. | 42| options | [MenuOptions](#menuoptions10) | No | Parameters of the context menu. | 43 44## bindContextMenu<sup>8+</sup> 45 46bindContextMenu(content: CustomBuilder, responseType: ResponseType, options?: ContextMenuOptions) 47 48Context menu bound to the component, which is displayed when the user long-presses or right-clicks the component. Only custom menu items are supported. 49 50**System capability**: SystemCapability.ArkUI.ArkUI.Full 51 52**Parameters** 53 54| Name | Type | Mandatory| Description | 55| ------------ | -------------------------------------------------- | ---- | -------------------------------------------- | 56| content | [CustomBuilder](ts-types.md#custombuilder8) | Yes | Array of menu item icons and text, or custom component.| 57| responseType | [ResponseType](ts-appendix-enums.md#responsetype8) | Yes | How the context menu is triggered, which can be long-press or right-click. | 58| options | [MenuOptions](#menuoptions10) | No | Parameters of the context menu. | 59 60## MenuElement 61 62| Name | Type | Mandatory| Description | 63| --------------------- | -------------------------------------- | ---- | ------------------------------------------------------------ | 64| value | string | Yes | Menu item text. | 65| icon<sup>10+</sup> | [ResourceStr](ts-types.md#resourcestr) | No | Menu item icon. | 66| enabled<sup>11+</sup> | boolean | No | Whether to enable interactions with the menu item.<br>Default value: **true**, indicating that interactions with the menu item are enabled.| 67| action | () => void | Yes | Action triggered when a menu item is clicked. | 68 69## MenuOptions<sup>10+</sup> 70 71Inherited from [ContextMenuOptions](#contextmenuoptions10). 72 73| Name | Type | Mandatory| Description | 74| ----------------------------- | -------------------------------------------- | ---- | ------------------------------------------------------------ | 75| title | string | No | Menu title.<br>**NOTE**<br>This parameter is effective only when **content** is set to Array<[MenuElement](#menuelement)>.| 76| offset | [Position](ts-types.md#position8) | No | Offset for showing the context menu, which should not cause the menu to extend beyond the screen.<br>**NOTE**<br>When the menu is displayed relative to the parent component area, the width or height of the area is automatically counted into the offset based on the **placement** attribute of the menu.<br>When the menu is displayed above the parent component (that is, **placement** is set to **Placement.TopLeft**, **Placement.Top**, or **Placement.TopRight**), a positive value of **x** indicates rightward movement relative to the parent component, and a positive value of **y** indicates upward movement.<br>When the menu is displayed below the parent component (that is, **placement** is set to **Placement.BottomLeft**, **Placement.Bottom**, or **Placement.BottomRight**), a positive value of **x** indicates rightward movement relative to the parent component, and a positive value of **y** indicates downward movement.<br>When the menu is displayed on the left of the parent component (that is, **placement** is set to **Placement.LeftTop**, **Placement.Left**, or **Placement.LeftBottom**), a positive value of **x** indicates leftward movement relative to the parent component, and a positive value of **y** indicates downward movement.<br>When the menu is displayed on the right of the parent component (that is, **placement** is set to **Placement.RightTop**, **Placement.RightTop**, or **Placement.RightBottom**), a positive value of **x** indicates rightward movement relative to the parent component, and a positive value of **y** indicates downward movement.<br>If the display position of the menu is adjusted (different from the main direction of the initial **placement** value), the offset value is invalid.| 77| placement | [Placement](ts-appendix-enums.md#placement8) | No | Preferred position of the context menu. If the set position is insufficient for holding the component, it will be automatically adjusted.<br>**NOTE**<br>If **placement** is set to **undefined** or **null** or is not set, the default value [BottomLeft](ts-appendix-enums.md#placement8) is used, and the position is relative to the parent component.| 78| onAppear | () => void | No | Callback triggered when the menu is displayed. | 79| onDisappear | () => void | No | Callback triggered when the menu is hidden. | 80| showInSubWindow<sup>11+</sup> | boolean | No | Whether to show the menu in a subwindow. | 81 82## ContextMenuOptions<sup>10+</sup> 83 84| Name | Type | Mandatory| Description | 85| --------------------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 86| offset | [Position](ts-types.md#position8) | No | Offset for showing the context menu, which should not cause the menu to extend beyond the screen.<br>**NOTE**<br>When the menu is displayed relative to the parent component area, the width or height of the area is automatically counted into the offset based on the **placement** attribute of the menu.<br>When the menu is displayed above the parent component (that is, **placement** is set to **Placement.TopLeft**, **Placement.Top**, or **Placement.TopRight**), a positive value of **x** indicates rightward movement relative to the parent component, and a positive value of **y** indicates upward movement.<br>When the menu is displayed below the parent component (that is, **placement** is set to **Placement.BottomLeft**, **Placement.Bottom**, or **Placement.BottomRight**), a positive value of **x** indicates rightward movement relative to the parent component, and a positive value of **y** indicates downward movement.<br>When the menu is displayed on the left of the parent component (that is, **placement** is set to **Placement.LeftTop**, **Placement.Left**, or **Placement.LeftBottom**), a positive value of **x** indicates leftward movement relative to the parent component, and a positive value of **y** indicates downward movement.<br>When the menu is displayed on the right of the parent component (that is, **placement** is set to **Placement.RightTop**, **Placement.RightTop**, or **Placement.RightBottom**), a positive value of **x** indicates rightward movement relative to the parent component, and a positive value of **y** indicates downward movement.<br>If the display position of the menu is adjusted (different from the main direction of the initial **placement** value), the offset value is invalid.| 87| placement | [Placement](ts-appendix-enums.md#placement8) | No | Preferred position of the context menu. If the set position is insufficient for holding the component, it will be automatically adjusted.<br>**NOTE**<br>Setting **placement** to **undefined** or **null** is equivalent to not setting it at all, and the context menu is displayed where the mouse is clicked.| 88| enableArrow | boolean | No | Whether to display an arrow. If the size and position of the context menu are insufficient for holding an arrow, no arrow is displayed.<br>Default value: **false**, indicating that no arrow is displayed<br>**NOTE**<br>When **enableArrow** is **true**, an arrow is displayed in the position specified by **placement**. If **placement** is not set or its value is invalid, the arrow is displayed above the target. If the position is insufficient for holding the arrow, it is automatically adjusted. When **enableArrow** is **undefined**, no arrow is displayed.| 89| arrowOffset | [Length](ts-types.md#length) | No | Offset of the arrow relative to the context menu. When the arrow is placed in a horizontal position with the context menu: The value indicates the distance from the arrow to the leftmost; the arrow is centered by default. When the arrow is placed in a vertical position with the context menu: The value indicates the distance from the arrow to the top; the arrow is centered by default. The offset settings take effect only when the value is valid, can be converted to a number greater than 0, and does not cause the arrow to extend beyond the safe area of the context menu. The value of **placement** determines whether the offset is horizontal or vertical.| 90| preview<sup>11+</sup> | [MenuPreviewMode](ts-appendix-enums.md#menupreviewmode11)\| [CustomBuilder](ts-types.md#custombuilder8) | No | Preview displayed when the context menu is triggered by a long-press. It can be a screenshot of the target component or custom content.<br>Default value: **MenuPreviewMode.NONE**, indicating no preview.<br>**NOTE**<br>- This parameter is effective only when **responseType** is set to **ResponseType.LongPress**.<br>- If **preview** is set to **MenuPreviewMode.NONE** or is not set, the **enableArrow** parameter is effective.<br>- If **preview** is set to **MenuPreviewMode.IMAGE** or **CustomBuilder**, no arrow will be displayed even when **enableArrow** is **true**.| 91| previewAnimationOptions<sup>11+</sup> | [ContextMenuAnimationOptions](#contextmenuanimationoptions11) | No | Start scale ratio and end scale ratio (relative to the original preview image) of the preview animation displayed when the component is long pressed<br>Default value: **{scale: [0.95, 1.1]}**<br>**NOTE**<br>- If the value of this parameter is less than or equal to 0, this parameter does not take effect.<br>- This parameter takes effect only when **preview** is set to **MenuPreviewMode.IMAGE.**| 92| onAppear | () => void | No | Callback triggered when the menu is displayed. | 93| onDisappear | () => void | No | Callback triggered when the menu is hidden. | 94| aboutToAppear | () => void | No | Callback triggered when the menu is about to appear. | 95| aboutToDisappear | () => void | No | Callback triggered when the menu is about to disappear. | 96| backgroundColor<sup>11+</sup> | [ResourceColor](ts-types.md#resourcecolor) | No| Backplane color of the dialog box.<br>Default value: **Color.Transparent**| 97| backgroundBlurStyle<sup>11+</sup> | [BlurStyle](ts-appendix-enums.md#blurstyle9) | No| Background blur style of the dialog box.<br>Default value: **BlurStyle.COMPONENT_ULTRA_THICK**| 98 99## ContextMenuAnimationOptions<sup>11+</sup> 100 101| Name | Type | Mandatory| Description | 102| ----- | ------------------------------------------ | ---- | ------------------------------------ | 103| scale | [AnimationRange](#animationrange11)\<number> | No | Scale ratio of the preview image when the animation starts and scale ratio when the animation ends.| 104 105## AnimationRange<sup>11+</sup> 106 107Describes the scale ratio of the preview image when the animation starts and scale ratio when the animation ends. 108 109**System capability**: SystemCapability.ArkUI.ArkUI.Full 110 111| Value Range | Description | 112| ---------------- | ------------------------------------------------------------------------------ | 113| [from: T, to: T] | **from** indicates the scale ratio of the preview image when the animation starts, and **to** indicates the scale ratio when the animation ends.| 114 115## Example 116 117### Example 1 118 119Menu with Textual Menu Items 120 121```ts 122// xxx.ets 123@Entry 124@Component 125struct MenuExample { 126 build() { 127 Column() { 128 Text('click for Menu') 129 } 130 .width('100%') 131 .margin({ top: 5 }) 132 .bindMenu([ 133 { 134 value: 'Menu1', 135 action: () => { 136 console.info('handle Menu1 select') 137 } 138 }, 139 { 140 value: 'Menu2', 141 action: () => { 142 console.info('handle Menu2 select') 143 } 144 }, 145 ]) 146 } 147} 148``` 149 150 151 152### Example 2 153 154Menu with Custom Menu Items 155 156```ts 157@Entry 158@Component 159struct MenuExample { 160 @State listData: number[] = [0, 0, 0] 161 162 @Builder MenuBuilder() { 163 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 164 ForEach(this.listData, (item:number, index) => { 165 Column() { 166 Row() { 167 Image($r("app.media.icon")).width(20).height(20).margin({ right: 5 }) 168 Text(`Menu${index as number + 1}`).fontSize(20) 169 } 170 .width('100%') 171 .height(30) 172 .justifyContent(FlexAlign.Center) 173 .align(Alignment.Center) 174 .onClick(() => { 175 console.info(`Menu${index as number + 1} Clicked!`) 176 }) 177 178 if (index != this.listData.length - 1) { 179 Divider().height(10).width('80%').color('#ccc') 180 } 181 }.padding(5).height(40) 182 }) 183 }.width(100) 184 } 185 186 build() { 187 Column() { 188 Text('click for menu') 189 .fontSize(20) 190 .margin({ top: 20 }) 191 .bindMenu(this.MenuBuilder) 192 } 193 .height('100%') 194 .width('100%') 195 .backgroundColor('#f0f0f0') 196 } 197} 198``` 199 200 201 202### Example 3 203 204Context Menu Displayed Upon Right-Click 205 206```ts 207// xxx.ets 208@Entry 209@Component 210struct ContextMenuExample { 211 @Builder MenuBuilder() { 212 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) { 213 Text('Test menu item 1') 214 .fontSize(20) 215 .width(100) 216 .height(50) 217 .textAlign(TextAlign.Center) 218 Divider().height(10) 219 Text('Test menu item 2') 220 .fontSize(20) 221 .width(100) 222 .height(50) 223 .textAlign(TextAlign.Center) 224 }.width(100) 225 } 226 227 build() { 228 Column() { 229 Text('rightclick for menu') 230 } 231 .width('100%') 232 .margin({ top: 5 }) 233 .bindContextMenu(this.MenuBuilder, ResponseType.RightClick) 234 } 235} 236``` 237 238### Example 4 239 240Directive Menu Displayed Upon Right-Click 241 242```ts 243// xxx.ets 244@Entry 245@Component 246struct DirectiveMenuExample { 247 @Builder MenuBuilder() { 248 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 249 Text('Options') 250 Divider().strokeWidth(2).margin(5).color('#F0F0F0') 251 Text('Hide') 252 Divider().strokeWidth(2).margin(5).color('#F0F0F0') 253 Text('Exit') 254 } 255 .width(200) 256 } 257 258 build() { 259 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 260 Column() { 261 Text("DirectiveMenuExample") 262 .fontSize(20) 263 .width('100%') 264 .height("25%") 265 .backgroundColor('#F0F0F0') 266 .textAlign(TextAlign.Center) 267 .bindContextMenu(this.MenuBuilder, ResponseType.RightClick, { 268 enableArrow: true, 269 placement: Placement.Bottom 270 }) 271 } 272 } 273 .width('100%') 274 .height('100%') 275 } 276} 277``` 278 279 280 281### Example 5 282 283Context Menu Displayed Upon Long-Pressing (with Preview of Component Screenshot) 284 285```ts 286// xxx.ets 287@Entry 288@Component 289struct Index { 290 private iconStr: ResourceStr = $r("app.media.icon") 291 292 @Builder 293 MyMenu() { 294 Menu() { 295 MenuItem({ startIcon: this.iconStr, content: "Menu option" }) 296 MenuItem({ startIcon: this.iconStr, content: "Menu option" }) 297 MenuItem({ startIcon: this.iconStr, content: "Menu option" }) 298 } 299 } 300 301 build() { 302 Column({ space: 50 }) { 303 Column() { 304 Column() { 305 Text('preview-image') 306 .width(200) 307 .height(100) 308 .textAlign(TextAlign.Center) 309 .margin(100) 310 .fontSize(30) 311 .bindContextMenu(this.MyMenu, ResponseType.LongPress, 312 { preview: MenuPreviewMode.IMAGE, 313 previewAnimationOptions: {scale: [0.8, 1.0]}, 314 }) 315 .backgroundColor("#ff3df2f5") 316 } 317 }.width('100%') 318 } 319 } 320} 321``` 322 323 324 325### Example 6 326 327Context Menu Displayed Upon Long-Pressing (with Preview of Custom Content) 328 329```ts 330// xxx.ets 331@Entry 332@Component 333struct Index { 334 private iconStr: ResourceStr = $r("app.media.icon") 335 336 @Builder 337 MyMenu() { 338 Menu() { 339 MenuItem({ startIcon: this.iconStr, content: "Menu option" }) 340 MenuItem({ startIcon: this.iconStr, content: "Menu option" }) 341 MenuItem({ startIcon: this.iconStr, content: "Menu option" }) 342 } 343 } 344 345 @Builder 346 MyPreview() { 347 Column() { 348 Image($r('app.media.icon')) 349 .width(200) 350 .height(200) 351 } 352 } 353 354 build() { 355 Column({ space: 50 }) { 356 Column() { 357 Column() { 358 Text('preview-builder') 359 .width(200) 360 .height(100) 361 .textAlign(TextAlign.Center) 362 .margin(100) 363 .fontSize(30) 364 .bindContextMenu(this.MyMenu, ResponseType.LongPress, 365 { 366 preview: this.MyPreview 367 }) 368 } 369 }.width('100%') 370 } 371 } 372} 373``` 374 375 376