Modal windows is an essential component in modern web design. Its primary use is to break complex actions into small, manageable tasks, bringing focus to the task at hand. This article will focus on an example where a modal window is used as a dialog to confirm a ‘Delete’ action. The article will detail the steps to create a modal dialog component and wire it on a given Power Apps screen.

Dialog design considerations:

Following are some general guidelines and considerations:

  • Dialog should only include the information needed to decide (on the action to be taken); any other information should be omitted (potentially displayed as part of the primary UI).
  • Complex decision making that requires additional sources of information should be avoided.
  • Dialog should be limited to three buttons or fewer.
  • Consider if the information displayed is important enough to interrupt the user.
  • Consider how frequently the information will need to be shown.  If user is expected to perform a particular action frequently, provide a way to undo the action (in case a mistake was made), rather than forcing the confirmation every time.
  • Generic buttons (ex. “OK”) should be avoided. The button label should state the action that is to be taken (ex. “Save”, “Delete”, “Cancel”, “Download”, etc.).

Modal dialog components:

Modal dialog is comprised of three components:

  • Background overlay to emphasize the dialog prompt and action buttons. The overlay should not be too dark as to provide sufficient view of the context, nor should it be too light as to remove any distractions.
  • Title and prompt to provide context to the listed action button(s).
  • Button(s) to fire off the given action(s).

Design Objectives:

  • The dialog is to be reusable (a component).
  • The component is to expose a property to open and close it.
  • The component is to expose a property to manipulate the title.
  • The component is to expose a property to manipulate the prompt/description.
  • The component is to expose a property to manipulate the overlay color.
  • The component is to allow for dynamic buttons.
  • The component is to expose its state (open/closed).
  • The component is to expose the selected button (label).

Implementing the dialog:

Add a Component named “Dialog”.

Set the ‘Size’ properties as follows:

  • ‘Width’: “App.Width” to extend the component over the entire application width.
  • ‘Height’: “App.Height” to extend the component over the entire application height.

Set the ‘Description’ to “Are you sure you want to proceed?”.

Add the below (Custom) Properties to the “Dialog” component:

Add a Rectangle control to be used as overlay.

Set the ‘Size’ properties as follows:

  • ‘Width’: “App.Width” to extend the overlay over the entire application width.
  • ‘Height’: “App.Height” to extend the overlay over the entire application height.

Set the ‘Fill’ property to “Dialog.OverlayColor” (the exposed ‘OverlayColor’ property).

Add a Container layout, “Controls”, to group the dialog prompt controls (i.e. the title, prompt text, and buttons)

Set the ‘Visible’ property to “Dialog.IsOpen” (the exposed ‘IsOpen’ property)

Set the ‘Position’ (X/Y) and ‘Size’ (Width/Height) properties to the desired location and size for the prompt.

Add a Rectangle control, “rectDialog”, under the ‘Controls’ container to house the prompt controls.

Set the ‘Width’ property to “Parent.Width” to inherit the ‘Width’ of the ‘Controls’ container.

For the time being set the ‘Height’ property to 142.
Note: The ‘Height’ property value will be adjusted to be set dynamically based on the combined heights of the controls contained within.

Set the Color (Fill) property to “If(!IsBlank(LookUp(Dialog.Styles, Key = “DialogFill”).Value),ColorValue(LookUp(Dialog.Styles, Key = “DialogFill”).Value), ColorValue(“#ffffff”))”.
Note: the above formula will look to retrieve the Color from the Styles (exposed property) table record with a key of “DialogFill”. If the key is not found, it will default to “ColorValue(“#ffffff”))” (white).

Add a Label control, “lblTitle”, under the ‘Controls’ container to house the dialog title.

Set the ‘Text’ property to “Dialog.Title” (the exposed ‘Title’ property)

Set the ‘Width’ property to “Parent.Width” to inherit the ‘Width’ of the ‘Controls’ container.

Set the ‘Font’ property to “If(!IsBlank(LookUp(Dialog.Styles, Key = “Font”).Value),LookUp(Dialog.Styles, Key = “Font”).Value, Font.’Segoe UI’)
Note: the above formula will look to retrieve the Font from the Styles (exposed property) table record with a key of “Font”. If the key is not found, it will default to ‘Segoe UI’.

Set the ‘Font Size’ property to “If(!IsBlank(LookUp(Dialog.Styles, Key = “DialogTitleFontSize”).Value),LookUp(Dialog.Styles, Key = “DialogTitleFontSize”).Value, 18)”
Note: the above formula will look to retrieve the Size from the Styles (exposed property) table record with a key of “DialogTitleFontSize”. If the key is not found, it will default to 18.

Add a Label control, “lblDescription”, under the ‘Controls’ container to house the dialog description.

Set the ‘Text’ property to “Dialog.Title” (the exposed ‘Description’ property)

Set the ‘Width’ property to “Parent.Width” to inherit the ‘Width’ of the ‘Controls’ container.

Set the ‘Y’ position property to “lblTitle.Y + lblTitle.Height + 5” to position below the title text.

Set the ‘Font’ property to “If(!IsBlank(LookUp(Dialog.Styles, Key = “Font”).Value),LookUp(Dialog.Styles, Key = “Font”).Value, Font.’Segoe UI’)
Note: the above formula will look to retrieve the Font from the Styles (exposed property) table record with a key of “Font”. If the key is not found, it will default to ‘Segoe UI’.

Set the ‘Font Size’ property to “If(!IsBlank(LookUp(Dialog.Styles, Key = “DialogDescriptionFontSize”).Value),LookUp(Dialog.Styles, Key = “DialogDescriptionFontSize”).Value, 16)”
Note: the above formula will look to retrieve the Size from the Styles (exposed property) table record with a key of “DialogDescriptionFontSize”. If the key is not found, it will default to 16.

Add a Gallery control, “ButtonGallery”, under the ‘Controls’ container to house the dialog buttons.

Set the ‘Y’ position property to “lblDescription.Y + lblDescription.Height” to position below the description text.

Set the ‘Width’ property to “Parent.Width” to inherit the ‘Width’ of the ‘Controls’ container.

Set the ‘TemplatSize’ property to “ButtonsGallery.Width / CountRows(ButtonsGallery.AllItems)” to evenly distribute the buttons.

Set the ‘Items’ property to “Dialog.Buttons” (exposed property) to pull in the button entries.

Add a Button control, “btnControl”, within the gallery.

Set the ‘Text’ property to “ThisItem.Label” to pull the Label property from the Buttons collection.

Set the ‘OnSelect’ action property to “Select(Parent)” to trigger the ‘OnSelect’ event on the parent (‘ButtonGallery’ control).

Set the ‘Fields’ (Data) property to btnControl.Label.

Set the ‘OnSelect’ action property to “Set(isButtonSelected, true); Set(isDialogOpen,false)”.
Note: “Set(isButtonSelected, true);” will set the ‘isButtonSelected’ variable to “true”. This variable will be used by the Toggle control to close the dialog.

“Set(isDialogOpen,false)” will set the ‘isDialogOpen’ variable to “false”. This variable will be used by Toggle control to set the dialog’s ‘open/close’ state.

Update the Dialog control, set the ‘SelectedButton’ property to “ButtonsGallery.Selected”, to point to the selected item within the ‘ButtonsGallery’ control. Doing so will expose the selected button (and its ‘Label’ property).

Update the Rectangle control, “rectDialog”:

Set the ‘Height’ property to “lblTitle.Height + lblDescription.Height + ButtonsGallery.Height + 15”. This will account for the 3 controls that are contained within and the spacing between them.

Add a Toggle control to control the ‘open/close’ state of the dialog.

Set the ‘Visible’ property to “false” to hide the toggle.

Set the ‘Default’ property to “Dialog.OpenClose” (exposed ‘OpenClose’ property). Changes to the property would trigger the toggle’s ‘Check’ and’ ‘UnCheck’ actions (events).

Set the ‘OnCheck’ action property to “Set(isButtonSelected, false);Set(isDialogOpen, true)”.
Note: the ‘OnCheck’ action will fire off when the OpenClose property gets set to “true”. The above formulas will deselect buttons and set ‘isDialogOpen’ variable to “true”, which will in turn set the ‘Dialog.IsOpen’ property to “true” and render the dialog window visible.

Set the ‘OnUncheck’ action property to “Set(isDialogOpen, false)”.
Note: the ‘OnUncheck’ action will fire off when the OpenClose property get set to “false”. The above formula will set ‘isDialogOpen’ variable to “false”, which will in turn set the ‘Dialog.IsOpen’ property to “false” and render the dialog window visible.

The resulting dialog:

Adding the Dialog component on a page (screen)

To utilize the created component, the component will need to be added onto a screen. A button will be used to trigger the dialog. An event handler in a form of Toggle control will be used to handle the Dialog’s button clicks (that will in turn fire off actions and close the dialog).

Insert the Dialog component onto a screen (Insert->Custom->Dialog), name it “CustomerDeleteDialog”.

Set the ‘CustomerDeleteDialog’ component properties as follows:

Add a ‘Delete’ button (icon) onto the screen.

Set the ‘OnSelect’ action property to “UpdateContext({varOpenCustDialog:false});UpdateContext({varOpenCustDialog:true});”.
Note: the above expression will set the ‘varOpenCustDialog’ variable to “true” and thus render the ‘CustomerDeleteDialog’ component visible.

Add a Toggle controller onto the screen to control whether the dialog is visible and to take action based on the dialog’s selected button.

Set the ‘OnUncheck’ action property to:
 “Switch(
    CustomerDeleteDialog.SelectedButton.Label,
    “Delete”,
    //Perform delete
   Notify(“Record Deleted”);
);
UpdateContext({varOpenCustDialog:false})”
Note: the above expression figures out what dialog button was clicked by checking the dialog’s ‘SelectedButton’ property and its underlying ‘Label’ value. In case the value is “Delete” a delete operation is performed. It then sets the ‘varOpenCustDialog’ variable to “false”, hiding the dialog.

Set the ‘Default’ property to “CustomerDeleteDialog.IsOpen”
Note: this is needed to keep track of the dialog’s ‘open/close’ state.

The resulting dialog: