When customizing Microsoft Dynamics 365 or a Model-Driven Power App, you may sometimes need to control which actions are available to users within lookup fields.
A common requirement is to hide the “New Document” button from a lookup dropdown, preventing users from creating new records directly from that interface.
In this article, we will explore a simple JavaScript solution that hides the button dynamically, even when the lookup control is refreshed or its content is re-rendered.
The JavaScript Solution
The following function hides the “New Document” button associated with the
dps_documentidlookup field._self.HideNewDocumentButton = function () { var s = 'button[data-id="dps_documentid.fieldControl-LookupResultsDropdown_dps_documentid_addNewBtnContainer"]', d; try { d = (window.parent && window.parent.document) || document; } catch (e) { d = document; } if (!d.getElementById("hideNewDocumentButtonStyle")) { var t = d.createElement("style"); t.id = "hideNewDocumentButtonStyle"; t.textContent = s + "{display:none!important}"; (d.head || d.documentElement).appendChild(t); } if (_self._hideBtnObserver) { _self._hideBtnObserver.disconnect(); } var h = function () { var b = d.querySelector(s); if (b) { b.style.display = "none"; } }; h(); _self._hideBtnObserver = new MutationObserver(h); _self._hideBtnObserver.observe(d.body, { childList: true, subtree: true }); };How Does It Work?
Let's break down the main components of this solution.
1. Identifying the Button
First, we define a CSS selector that identifies the specific button inside the lookup dropdown:
var s = 'button[data-id="dps_documentid.fieldControl-LookupResultsDropdown_dps_documentid_addNewBtnContainer"]';Using the
data-idattribute allows us to target the intended button without affecting other buttons in the application.2. Accessing the Parent Document
The function attempts to access the parent window's document:
try { d = (window.parent && window.parent.document) || document; } catch (e) { d = document; }This is useful in scenarios where the JavaScript code runs inside an embedded context.
If accessing the parent document is not possible, the function falls back to the current document.
Note that browser same-origin restrictions may prevent access to the parent document.
3. Injecting a CSS Rule
To ensure the button remains hidden, we dynamically inject a CSS rule into the document:
if (!d.getElementById("hideNewDocumentButtonStyle")) { var t = d.createElement("style"); t.id = "hideNewDocumentButtonStyle"; t.textContent = s + "{display:none!important}"; (d.head || d.documentElement).appendChild(t); }The style element is created only once, avoiding unnecessary duplicate CSS rules.
The
!importantdeclaration ensures that the button remains hidden even if other styles attempt to display it.4. Using MutationObserver
One of the main challenges with Dynamics 365 and Model-Driven Apps is that interface elements can be dynamically rendered.
This means that hiding a button only once may not be sufficient.
To solve this problem, we use the JavaScript
MutationObserverAPI:_self._hideBtnObserver = new MutationObserver(h); _self._hideBtnObserver.observe(d.body, { childList: true, subtree: true });The observer monitors changes in the document's DOM tree.
Whenever new elements are added, the callback checks whether the target button exists and hides it if necessary.
Before creating a new observer, the function disconnects any previously registered instance. This prevents multiple observers from running simultaneously.
Why Use MutationObserver?
Without a MutationObserver, the button could reappear whenever Dynamics 365 refreshes or rebuilds the lookup dropdown.
By monitoring DOM changes, we can automatically reapply the hiding logic whenever the relevant interface elements are rendered.
This makes the customization more resilient to dynamic UI updates.
Important Considerations
Although this approach can be useful for client-side interface customization, there are a few things to keep in mind:
DOM dependencies: The
data-idattribute may change after platform updates.Performance: Observing the entire document can generate frequent callbacks. For more complex applications, consider monitoring a smaller container.
Browser compatibility:
MutationObserveris supported by modern browsers.Security: Hiding a button does not prevent users from creating records through other interfaces, APIs, or alternative application paths.
Supported customization: Direct DOM manipulation of Dynamics 365 and Model-Driven App interfaces is not a supported customization mechanism and may break after updates.
If record creation must genuinely be restricted, implement the appropriate security roles, privileges, and server-side validation.
With a few lines of JavaScript and the MutationObserver API, it is possible to hide the “New Document” button from a specific Dynamics 365 lookup dropdown.
This technique demonstrates how to handle dynamically generated UI elements and apply targeted client-side customizations.
However, it should be considered a visual workaround rather than a security solution. Always use the platform's supported security mechanisms to enforce business rules and access restrictions.
Have you encountered similar challenges when customizing Dynamics 365 lookup controls? Share your experience in the comments!
_self.HideNewDocumentButton = function () { var buttonDataId = "dps_documentid.fieldControl-LookupResultsDropdown_dps_ documentid_addNewBtnContainer" ; var selector = 'button[data-id="' + buttonDataId + '"]'; var targetDoc; try { targetDoc = (window.parent && window.parent.document) ? window.parent.document : document; } catch (e) { targetDoc = document; } var styleId = "hideNewDocumentButtonStyle"; if (!targetDoc.getElementById(sty leId)) { var style = targetDoc.createElement(" style"); style.id = styleId; style.textContent = selector + " { display: none !important; }"; (targetDoc.head || targetDoc.documentElement).app endChild(style); } if (_self._hideBtnObserver) { _self._hideBtnObserver.disconn ect(); } var hideBtn = function () { var btn = targetDoc.querySelector(select or); if (btn) { btn.style.display = "none"; } }; hideBtn(); _self._hideBtnObserver = new MutationObserver(hideBtn); _self._hideBtnObserver.observe (targetDoc.body, { childList: true, subtree: true }); };
<!DOCTYPE html> <html lang="it"> <head> <meta charset="utf-8" /> <title>POC WebAssembly - Hide New Document Button</title> </head> <body> <h3>Proof of Concept: WebAssembly + DOM (Hide button)</h3> <button data-id="dps_documentid.