While working with the standard Show Confirmation JavaScript Action generated by Mendix, I noticed a limitation in the Web runtime that may affect projects requiring a more customized user experience.
The original implementation exposes a titleCaption parameter:
@param {string} titleCaption - Set to empty to use default text 'Confirmation'. (Only for native)
However, this parameter is only used when the application is running in a Native environment:
Alert.alert(title, question, ...)
For Web applications, the implementation relies on:
mx.ui.confirmation(...)
which displays the standard Mendix confirmation dialog but ignores the titleCaption parameter entirely. As a result, developers cannot dynamically define the dialog title from a Nanoflow when running on the Web.
The first enhancement adds support for custom dialog titles in Web applications.
Instead of injecting global CSS to replace the title, the solution uses a MutationObserver to detect the creation of the confirmation dialog and directly update the dialog header in the generated DOM.
titleCaption parameter consistently across Native and Web.From a developer perspective, the same parameter that already works in Native can now be used transparently in Web.
A second enhancement introduces an optional input parameter:
dialogClassName
When provided, the JavaScript Action adds the specified class to the generated dialog container:
<div class="modal-dialog mx-dialog my-custom-class">
Projects that do not provide a class continue to behave exactly as before.
With these two small changes, the action becomes significantly more flexible:
✅ Dynamic titles work in both Native and Web environments.
✅ Developers can optionally assign custom CSS classes to individual confirmation dialogs.
✅ No changes are required for existing implementations.
✅ The solution remains fully backward compatible.
I believe these improvements could make the standard Show Confirmation action more consistent across platforms and provide additional customization possibilities for Web applications without breaking existing projects.
/----------- Javascript action result ---------------/
// This file was generated by Mendix Studio Pro.
//
// WARNING: Only the following code will be retained when actions are regenerated:
// - the import list
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import "mx-global";
import { Big } from "big.js";
// BEGIN EXTRA CODE
// END EXTRA CODE
/**
* Shows a confirmation dialog during the execution of a nanoflow, to make perform actions based on the user input.
* @param {string} titleCaption - Set to empty to use default text 'Confirmation'. (Only for native)
* @param {string} question - This field is required.
* @param {string} cancelButtonCaption - Set to empty to use default text 'Cancel'.
* @param {string} proceedButtonCaption - Set to empty to use default text 'OK'.
* @param {string} [dialogClassName]
* @returns {Promise.<boolean>}
*/
export async function ShowConfirmationClassName(titleCaption, question, cancelButtonCaption, proceedButtonCaption, dialogClassName) {
// BEGIN USER CODE
if (!question) {
return Promise.reject(new Error("Input parameter 'Question' is required"));
}
const cancel = cancelButtonCaption || "Cancel";
const proceed = proceedButtonCaption || "OK";
const title = titleCaption || "Confirmation";
// Native platform
if (navigator && navigator.product === "ReactNative") {
const Alert = require("react-native").Alert;
return new Promise(resolve => {
Alert.alert(title, question, [
{ text: cancel, onPress: () => resolve(false), style: "cancel" },
{ text: proceed, onPress: () => resolve(true) }
]);
});
}
// Web
return new Promise(resolve => {
mx.ui.confirmation({
content: question,
proceed,
cancel,
handler: () => resolve(true),
onCancel: () => resolve(false)
});
const observer = new MutationObserver(() => {
const dialog = document.querySelector(
'[id^="mxui_widget_DialogMessage_"]'
);
if (!dialog) {
return;
}
if (dialogClassName) {
dialog.classList.add(dialogClassName);
}
const titleElement = dialog.querySelector(".modal-header h4");
if (titleElement && title) {
titleElement.textContent = title;
}
observer.disconnect();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
// END USER CODE
}