[BUG] Function getHiddenSelectedCountryWidth fails to calculate the correct offset width.
Plugin Version
v25.2.1
Steps to Reproduce
- Initialize the plugin with
separateDialCodeenabled. - Place the input field within a hidden container or an iframe during initialization.
- Observe that the
_getHiddenSelectedCountryWidthfunction fails to calculate the correct offset width.
Expected Behavior
The _getHiddenSelectedCountryWidth function should correctly calculate the offsetWidth of the selectedCountry element, even when the input is within a hidden container or iframe during initialization.
Actual Behavior
The _getHiddenSelectedCountryWidth function fails when the input is within an iframe or hidden container. This is likely because the document.body.appendChild(containerClone) operation does not correctly account for the DOM context, causing the width calculation to return incorrect or zero values.
Proposed Solution
The issue can be resolved by ensuring that the operation to append the containerClone occurs in the correct DOM context. For example, using window.top.document.body.appendChild(containerClone) ensures that the correct body element is targeted, even within an iframe.
See PR: #1934
Additional Notes
- The issue seems to stem from the fact that document.body might not be accessible or correctly referenced when the input is within an iframe.
- The proposed solution ensures that the correct DOM context is used for appending the containerClone.
- I am not totally sure about the potential sideffects it may cause for other environments such as Vue or React.
Hey @jackocnr , gentle ping 😉
@TheBlackSwannn apologies for the delay in getting to this - life has been getting in the way.
The _getHiddenSelectedCountryWidth function fails when the input is within an iframe or hidden container. This is likely because the document.body.appendChild(containerClone) operation does not correctly account for the DOM context, causing the width calculation to return incorrect or zero values.
I'm struggling to understand this. Why would it matter which DOM context the code is run in? It just duplicates an element and measures its width. I've tried playing around with iframes and I can't reproduce the issue.
Is there a way you can reproduce this issue in a CodePen for me to take a look at? Here is an example pen with the plugin up and running - feel free to fork this if it helps.
Your report says you see this issue even when just putting the input in a hidden container, which I can't reproduce. In fact, this is the very use case that we wrote this feature for. Please do provide a codepen or specific instructions to reproduce the issue if you're really seeing this issue.
Re: the iframe setup, I still can't wrap my head around your use case. The only thing I can think that might not work would be if you had the input in an iframe, but you were initialising the plugin from the outside of the iframe - is that the case? And maybe the iframe also has to be hidden? Anyway, I think this is such an edge case that I don't think it's worth messing with the code for this, because as you say, it may have unintended side effects in other contexts e.g. for the react/vue/angular components. I'll close this for now, but please do share a codepen etc if/when you have time.
Sorry for the delay. I can try to provide a CodePen/repro in the coming weeks if needed. In the meantime, here’s more context:
Our setup: we use next-intl inside an iframe that lives in a popup.
The issue: the JS inside the iframe runs before the popup has fully opened. As a result, the element whose width we measure is cloned while some parts of the UI are still not visible, so its computed width is incorrect.
My initial idea was to clone the element in the window context rather than the document context. Using document.body targets the iframe and is affected by the timing issue described above, while window.top feels “safer” because it’s outside the iframe.
I hope this clarifies the situation. If it’s not sufficient, I’ll try to find time to provide a minimal reproducible example.
Ok, just reading about this, and apparently if the iframe is from the same origin as the parent document, then the JS in the iframe can access the DOM in the parent. So I now understand what you're trying to do. But as an implementation note: we would need to guard against the cross-origin possibility, in which case window.top.document will throw an error.
Also, what about the other ways the plugin accesses the document object, e.g. the click event listener that handles click-off-to-close on the dropdown, or for the keydown event listener that handles navigating the dropdown list with up/down/enter/escape. Do these currently work inside an iframe? If not, do they work with the window.top fix?
Thank you for your answer.
Ok, just reading about this, and apparently if the iframe is from the same origin as the parent document, then the JS in the iframe can access the DOM in the parent. So I now understand what you're trying to do. But as an implementation note: we would need to guard against the cross-origin possibility, in which case window.top.document will throw an error.
You're absolutely right about the cross-origin issue that could throw an error, so it may be reasonable to avoid doing that. Instead, would it be possible to set a default minimum value when the returned width is zero or undefined? It might not be ideal for every country, but at least the UI error would be less noticeable. If you have any other relevant suggestions, I’d be glad to consider them carefully.
Also, what about the other ways the plugin accesses the document object, e.g. the click event listener that handles click-off-to-close on the dropdown, or for the keydown event listener that handles navigating the dropdown list with up/down/enter/escape. Do these currently work inside an iframe? If not, do they work with the window.top fix?
There are no issues with the other event listeners since they only execute once the popup containing the iframe is fully displayed.
I've implemented the window.top fix in v25.10.1 (and also added sane fallback values as well). Let me know if that works for you.
Hey, thank you for the fix and time spent investing our request.
We've tested it successfully, works like a charm! 👌