1# Global Popups Independent of UI Components (openPopup) 2 3The [Popup](arkts-popup-and-menu-components-popup.md) API is a great option for creating popups, but it relies on a bound UI component to work. Since API version 18, however, the global API [openPopup](../reference/apis-arkui/js-apis-arkui-UIContext.md#openpopup18) offers a more flexible solution. This API can be used directly or encapsulated in scenarios where no bound UI components are available, making it ideal for use cases such as event callbacks or when integrating with external systems. 4 5## Displaying a Popup 6 7To display a popup, call the [openPopup](../reference/apis-arkui/js-apis-arkui-UIContext.md#openpopup18) API. Here's a basic example: 8 9 ```ts 10 promptAction.openPopup(contentNode, { id: targetId }, { 11 enableArrow: true 12 }) 13 .then(() => { 14 console.info('openPopup success'); 15 }) 16 .catch((err: BusinessError) => { 17 console.info('openPopup error: ' + err.code + ' ' + err.message); 18 }) 19 ``` 20 21### Creating a ComponentContent Instance 22 23 When using **openPopup**, you need to provide a [ComponentContent](../reference/apis-arkui/js-apis-arkui-ComponentContent.md) instance to define the popup content. **wrapBuilder(buildText)** encapsulates the custom component, and **new Params(this.message)** is the input parameter for the custom component. This parameter is optional and can be a basic data type. 24 25 ```ts 26 private contentNode: ComponentContent<Object> = new ComponentContent(uiContext, wrapBuilder(buildText), this.message); 27 ``` 28 29 If your **wrapBuilder** includes other components (such as [Popup](../reference/apis-arkui/arkui-ts/ohos-arkui-advanced-Popup.md#popup) or [Chip](../reference/apis-arkui/arkui-ts/ohos-arkui-advanced-Chip.md#chip)), the [ComponentContent](../reference/apis-arkui/js-apis-arkui-ComponentContent.md#componentcontent-1) constructor must include four parameters, and the **options** parameter must be **{ nestingBuilderSupported: true }**. 30 31 ```ts 32 @Builder 33 export function buildText(params: Params) { 34 Popup({ 35 // Set the icon for the menu. 36 icon: { 37 image: $r('app.media.app_icon'), 38 width: 32, 39 height: 32, 40 fillColor: Color.White, 41 borderRadius: 10 42 } as PopupIconOptions, 43 // Set the text content. 44 title: { 45 text: `This is a Popup title 1`, 46 fontSize: 20, 47 fontColor: Color.Black, 48 fontWeight: FontWeight.Normal 49 } as PopupTextOptions, 50 // Set the text content. 51 message: { 52 text: `This is a Popup message 1`, 53 fontSize: 15, 54 fontColor: Color.Black 55 } as PopupTextOptions, 56 // Set the buttons. 57 buttons: [{ 58 text: 'confirm', 59 action: () => { 60 console.info('confirm button click') 61 }, 62 fontSize: 15, 63 fontColor: Color.Black, 64 }, 65 { 66 text: 'cancel', 67 action: () => { 68 console.info('cancel button click') 69 }, 70 fontSize: 15, 71 fontColor: Color.Black 72 },] as [PopupButtonOptions?, PopupButtonOptions?] 73 }) 74 } 75 76 let contentNode: ComponentContent<Object> = new ComponentContent(uiContext, wrapBuilder(buildText), this.message, { nestingBuilderSupported: true }); 77 ``` 78 79 80### Providing Bound Component Information 81 82 When calling **openMenu**, you must provide the [TargetInfo](../reference/apis-arkui/js-apis-arkui-UIContext.md#targetinfo18) of the bound component. Without a valid target, the popup won't display. 83 84 ```ts 85 let frameNode: FrameNode | null = this.ctx.getFrameNodeByUniqueId(this.getUniqueId()); 86 let targetId = frameNode?.getChild(0)?.getUniqueId(); 87 ``` 88 89### Customizing the Popup Style 90 91 When calling **openPopup**, you can customize the menu style using [PopupCommonOptions](../reference/apis-arkui/arkui-ts/ts-universal-attributes-popup.md#popupcommonoptions18). 92 93 ```ts 94 private options: PopupCommonOptions = { enableArrow: true }; 95 ``` 96 97## Updating the Popup Style 98 99To update the popup style, use the [updatePopup](../reference/apis-arkui/js-apis-arkui-UIContext.md#updatepopup18) API. You can update the style fully or incrementally. However, certain properties, including **showInSubWindow**, **focusable**, **onStateChange**, **onWillDismiss**, and **transition**, cannot be updated. 100 101 ```ts 102 promptAction.updatePopup(contentNode, { 103 enableArrow: false 104 }, true) 105 .then(() => { 106 console.info('updatePopup success'); 107 }) 108 .catch((err: BusinessError) => { 109 console.info('updatePopup error: ' + err.code + ' ' + err.message); 110 }) 111 ``` 112 113## Closing the Popup 114 115To close the popup, call the [closePopup](../reference/apis-arkui/js-apis-arkui-UIContext.md#closepopup18) API. 116 117 ```ts 118 promptAction.closePopup(contentNode) 119 .then(() => { 120 console.info('closePopup success'); 121 }) 122 .catch((err: BusinessError) => { 123 console.info('closePopup error: ' + err.code + ' ' + err.message); 124 }) 125 ``` 126 127> **NOTE** 128> 129> The [updatePopup](../reference/apis-arkui/js-apis-arkui-UIContext.md#updatepopup18) and [closePopup](../reference/apis-arkui/js-apis-arkui-UIContext.md#closepopup18) APIs rely on the content to identify the menu. Therefore, you must maintain the content instance throughout the popup's lifecycle. 130 131 132## Using the Global Popup in HAR Packages 133 134You can encapsulate a popup using the [HAR](../quick-start/har-package.md) package to provide display, update, and close capabilities. 135 136```ts 137// library/src/main/ets/components/MainPage.ets 138 139import { BusinessError } from '@kit.BasicServicesKit'; 140import { ComponentContent, TargetInfo, PromptAction } from '@kit.ArkUI'; 141 142export class PromptActionClass { 143 private promptAction: PromptAction | null = null; 144 private contentNode: ComponentContent<Object> | null = null; 145 private options: PopupCommonOptions | null = null; 146 private target: TargetInfo | null = null; 147 private isPartialUpdate: boolean = false 148 149 public setPromptAction(promptAction: PromptAction) { 150 this.promptAction = promptAction; 151 } 152 153 public setContentNode(node: ComponentContent<Object>) { 154 this.contentNode = node; 155 } 156 157 public setTarget(target: TargetInfo) { 158 this.target = target; 159 } 160 161 public setOptions(options: PopupCommonOptions) { 162 this.options = options; 163 } 164 165 public setIsPartialUpdate(isPartialUpdate: boolean) { 166 this.isPartialUpdate = isPartialUpdate; 167 } 168 169 public openPopup() { 170 if (this.promptAction != null) { 171 this.promptAction.openPopup(this.contentNode, this.target, this.options) 172 .then(() => { 173 console.info('openPopup success'); 174 }) 175 .catch((err: BusinessError) => { 176 console.info('openPopup error: ' + err.code + ' ' + err.message); 177 }) 178 } 179 } 180 181 public closePopup() { 182 if (this.promptAction != null) { 183 this.promptAction.closePopup(this.contentNode) 184 .then(() => { 185 console.info('closePopup success'); 186 }) 187 .catch((err: BusinessError) => { 188 console.info('closePopup error: ' + err.code + ' ' + err.message); 189 }) 190 } 191 } 192 193 public updatePopup(options: PopupCommonOptions) { 194 if (this.promptAction != null) { 195 this.promptAction.updatePopup(this.contentNode, options, this.isPartialUpdate) 196 .then(() => { 197 console.info('updatePopup success'); 198 }) 199 .catch((err: BusinessError) => { 200 console.info('updatePopup error: ' + err.code + ' ' + err.message); 201 }) 202 } 203 } 204} 205``` 206 207```ts 208// entry/src/main/ets/pages/Index.ets 209 210import { PromptActionClass } from "library"; 211import { ComponentContent, PromptAction } from '@kit.ArkUI'; 212 213class Params { 214 text: string = "" 215 promptActionClass: PromptActionClass = new PromptActionClass(); 216 217 constructor(text: string, promptActionClass: PromptActionClass) { 218 this.text = text; 219 this.promptActionClass = promptActionClass; 220 } 221} 222 223@Builder 224function buildText(params: Params) { 225 Column() { 226 Text(params.text) 227 .fontSize(20) 228 .margin({ top: 10 }) 229 Button('Update') 230 .margin({ top: 10 }) 231 .width(100) 232 .onClick(() => { 233 params.promptActionClass.updatePopup({ 234 enableArrow: false, 235 }) 236 }) 237 Button('Close') 238 .margin({ top: 10 }) 239 .width(100) 240 .onClick(() => { 241 params.promptActionClass.closePopup() 242 }) 243 }.width(130).height(150) 244} 245 246@Entry 247@Component 248struct Index { 249 @State message: string = "hello" 250 private uiContext: UIContext = this.getUIContext(); 251 private promptAction: PromptAction = this.uiContext.getPromptAction(); 252 private promptActionClass: PromptActionClass = new PromptActionClass(); 253 private targetId: number = 0; 254 private contentNode: ComponentContent<Object> = 255 new ComponentContent(this.uiContext, wrapBuilder(buildText), new Params(this.message, this.promptActionClass)); 256 private options: PopupCommonOptions = { enableArrow: true }; 257 258 build() { 259 Column() { 260 Button("openPopup") 261 .margin({ top: 50, left: 100 }) 262 .onClick(() => { 263 let frameNode: FrameNode | null = this.uiContext.getFrameNodeByUniqueId(this.getUniqueId()); 264 let targetId = frameNode?.getChild(0)?.getUniqueId(); 265 if (targetId == undefined) { 266 this.targetId = 0; 267 } else { 268 this.targetId = targetId; 269 } 270 this.promptActionClass.setPromptAction(this.promptAction); 271 this.promptActionClass.setContentNode(this.contentNode); 272 this.promptActionClass.setOptions(this.options); 273 this.promptActionClass.setIsPartialUpdate(false); 274 this.promptActionClass.setTarget({ id: this.targetId }); 275 this.promptActionClass.openPopup(); 276 }) 277 } 278 } 279} 280``` 281 282 283