If there’s one down-side to JQuery UI dialogs, then it’s that they can be too simple to use and too much of the actual logic is hidden from the developer’s view. This can easily end up with surprising behavior which can only be described as the control trying to be too clever and to do too much behind the scenes.
Troubleshooting the Dialog Positioning Problem
For example, when I was working with a dialog using the JQuery 1.7 and UI 1.8 libraries, I noticed that in certain situations the dialog window would sometimes randomly position itself, including positioning itself partially off the page it was embedded in. This was certainly not the logic I was intending. The positioning trouble would happen rarely in a full size window but fairly consistently in a window that was set to a smaller size than the dialog. I should also mention that the a second condition for seeing the positioning problem would be that the dialog was set to appear in a scrollable window with lots of content, where the user had scrolled midway through the page.
After scratching my head and wondering what could be causing the dialog to behave this way, I figured out that something called the JQuery dialog’s collision detection was acting up. At the time I had no idea that this was working hard in the background, trying rather heroically to save developers from badly positioning their dialogs. However in my case it was causing the mysterious positioning problems, placing the dialog window partially off the Web page. So uncovering the effect of the collision detection was a fairly important finding in troubleshooting the strange behavior I was seeing. And once I figured out how to disable collision detection, the window would position itself very nicely and exactly where I told it to.
Correcting the Dialog Positioning
So how does collision detection work and why was it causing strange problems with my dialog? It seems that collision detection is coded to try to detect if the dialog is being set to appear where it shouldn’t (for example off the Web page). If it decides that the developer has positioned it incorrectly then it will then try various tricks including flipping vertical or horizontal positioning instructions that you have given it to correct the collision. In my testing this has caused more problems than it has solved.
It’s also important to note that along with disabling the dialog’s collision detection, I needed to set the position of the dialog to be ‘fixed‘ in order for me to be able to set it to show at the top left of the user’s active window regardless of how far down on the page the user had scrolled.
The collision detection was trying to be smarter than it actually was and it would randomly force the dialog off the user’s active window and off the page, making it randomly un-usable. I was quite glad to find out how to disable this by both setting the dialog’s position to fixed and disabling collision detection.
Setting up the JQuery UI Dialog Parameters
For starters we have to tell JQuery how to set up and display the new dialog on our page. To do so, we set add the following code:
$("#dialogEditSomeText").dialog({ height: viewportHeight, width: viewportWidth, autoOpen: false, modal: false, resizable: true , position: { my: "left top", at: "left top", of: window, collision: "none" } , create: function (event, ui) { $(event.target).parent().css('position', 'fixed'); } });
I’ll explain the height and width parameters in a section below. If you don’t want to dynamically size your dialog then you can just type in the numbers directly in this setup function.
As you can see, the parameters are fairly standard for establishing a new dialog. We set it to not open automatically when the page is first loaded using: autoOpen: false;
Then depending on your needs, you can set your dialog to be modal or not. This doesn’t really affect our positioning problems. Likewise the resizable option can be set as you like. It also doesn’t play a role in positioning issues.
However what is important is to set your positioning parameters. In this case we want the dialog to appear aligned to the top left corner of the user’s viewable browser window, no matter where on the page they have scrolled. You need to do this specifically using the positioning directives:
position: { my: "left top", at: "left top", of: window, collision: "none" }
Notice that these directives read almost in plain English to what we want the dialog to do. One very important part to include is the collision: “none” option. As I mentioned earlier in the article, this is a key in forcing the dialog to appear where you want it to be, without the dialog trying to second guess your instructions
Finally, you also need to set the position of your dialog to a fixed positon in the user’s window. This is important in getting the dialog to show exactly where you want it to show. You set this instruction as:
, create: function (event, ui) { $(event.target).parent().css('position', 'fixed'); }
Setting the Dialog Size to Match the Size of the User’s Browser Window
For extra points, I dynamically set the size of the dialog window so that if the user’s browser window is set to be smaller than the optimum size of the dialog window, the dialog will adjust its size to fit into the size of the user’s browser window with scroll bars enabled. I did this using the JavaScript window.innerWidth and window.innerHeight properties. Below I’m including a working example of this.
var viewportWidth = window.innerWidth-20; var viewportHeight = window.innerHeight-20; if (viewportWidth > 1000) viewportWidth = 1000; if (viewportHeight > 500) viewportHeight = 500;
As you can see from the code above, the first two lines get the height and width of the currently open browser window. The code also adjusts the value to -20 pixels since I have found this to be necessary to give a nice amount of buffer to the size.
Then you can see in the last two lines that the maximum size of the popup dialog is being set. If the currently open browser window is more than 1000 pixels wide and 500 pixels high, then the code limits the size of the dialog to these dimensions to avoid an overly large dialog. Otherwise if the window is smaller, then the dialog is set to occupy the full amount of space available.
These sizing parameters are set in the dialog initialization code as follows:
$("#dialogEditSomeText").dialog({ height: viewportHeight, width: viewportWidth,
The Example Code
Below I’m providing a fully functional example page of the concepts I’ve been talking about in this article. To run this example, just copy and paste the code into a notepad window and open the file using the browser of your choice.
To test the JQuery dialog functionality, make your window small enough for a scroll bar to show up at the right hand side. I have added a bunch of random text to the file so you can scroll down to the bottom of the page. Click the button at the bottom of the page to see the dialog appear. You will happily note that the dialog always appears nicely aligned at the top left hand side of your browser window.
<html> <head> <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script> </head> <body> <p> Just a note: make sure your window is sized small so the right hand side scroll-bar appears. Then scroll to the bottom of the page and click the button there titled 'Click here to open the test dialog'. You will see that the dialog is always properly positioned at the top left of your window. </p><p> The standard Lorem Ipsum passage, used since the 1500s </p><p> "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut <br>labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco <br>laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in <br>voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat<br> non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." </p><p> Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC </p><p> "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium,<br> totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto<br> beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit <br>aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem <br>sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, <br>adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam <br>aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam <br>corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum <br>iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum <br>qui dolorem eum fugiat quo voluptas nulla pariatur?" </p><p> 1914 translation by H. Rackham </p><p> "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was<br> born and I will give you a complete account of the system, and expound the actual teachings<br> of the great explorer of the truth, the master-builder of human happiness. No one <br>rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do<br> not know how to pursue pleasure rationally encounter consequences that are extremely <br>painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, <br>because it is pain, but because occasionally circumstances occur in which toil and pain can <br>procure him some great pleasure. To take a trivial example, which of us ever undertakes <br>laborious physical exercise, except to obtain some advantage from it? But who has any right to <br>find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one<br> who avoids a pain that produces no resultant pleasure?" </p> <div id="dialogEditSomeText" title="Demo JQuery UI Dialog properly positioned" style="display:none; overflow:hidden; margin:0; padding:0;"> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p> </div> <input type="button" id="btnClickMe" value="Click here to open the test dialog"> <script> var viewportWidth = window.innerWidth-20; var viewportHeight = window.innerHeight-20; if (viewportWidth > 1000) viewportWidth = 1000; if (viewportHeight > 500) viewportHeight = 500; $("#dialogEditSomeText").dialog({ height: viewportHeight, width: viewportWidth, autoOpen: false, modal: false, resizable: true , position: { my: "left top", at: "left top", of: window, collision: "none" } , create: function (event, ui) { $(event.target).parent().css('position', 'fixed'); } }); $( "#btnClickMe" ).click(function() { $( "#dialogEditSomeText" ).dialog( "open" ); }); </script> </body> </html>
Thanks this was life saver!
Hm.. my view port content positioned fine after all, but posiotion of scroll bar grip itself (thing that you holding with a mouse to move it here and there) doesn’t match the posiotion of the content. Is it how ut was for you?
Thank you, your article has been very helpful!
Ninja dude!
Thanks Justin, very useful solution.
Thanks for letting me know the info was helpful, have a great day!
You’re my hero – banged my head against the wall with this for awhile. Thanks a lot!
Thank you very very much.
This was helpful, except if I have the dialog open at the ‘center center’ position the page scrolls to the top. “return false” doesn’t cure it.
I cured that by using a scrollTo setting inside the close:function
Also … the way of determining the width is neat, but if I give a width of 30 percent of the viewport, that looks bad on mobile. Yet with no width specified, the widths seem to accommodate differently for desktop and mobile (though not to my liking) … I’m just wondering how to use whatever specifies that to vary desktop and mobile width separately… ?