A cross-browser JavaScript prompt

You might be looking at the title of this entry and say “Well, DUH! JavaScript’s prompt() is already cross-browser!”

While working on a project earlier today, I discovered a nasty little problem… Internet Explorer v7 (IE7) disables prompt() by default! This means you can’t rely on prompt() being available in IE7 when building your online applications.

In most cases, prompt() should be avoided altogether. Maybe Microsoft was right in disabling prompt(), since so many malicious sites take advantage of it. However, I had a legitimate use for it today, and was very irked to find out it won’t work in IE7. (I develop in Firefox and IE6, which might explain to some of you why I’m late to the party with discovering this limitation in IE7.)

After googling for a while — yes, I use google as a verb — it appears quite a few people have developed workarounds for the prompt() limitation in IE7. Most of them were bulky or required a bit too much hacking for my tastes. There were a few nice examples [link no longer available] out there, but in the end, I decided to make my own workaround using Microsoft’s proprietary showModalDialog function.

Microsoft’s showModalDialog allows the developer to load an external HTML file into a generated window and give it focus. The user can’t click back to the original document until they’ve closed the modal window, just like a prompt(), alert(), or confirm(). The generated window behaves much like a pop-up window (it can be sized, show/hide scrollbars, etc.), but to my knowledge, modal windows aren’t blocked by pop-up blockers.

I’ll admit that using an external HTML page feels like a big disadvantage compared to a simple prompt(). However, one potential advantage showModalWindow provides is the ability to style the faux prompt window; in IE, the prompt window has always looked and behaved a little different from any of the other dialog windows (alert, confirm). Now we can have it visually fit in with the rest of the family! Due to this styling issue, and to make my life easier, I decided to use showModalWindow on all versions of IE, not just IE7.

Native IE6 prompt:
Native IE6 prompt

Native Firefox 2 prompt:
Native Firefox 2 prompt

New faux prompt, as seen in IE6:
Faux prompt, IE6

New faux prompt, as seen in IE7 (WinXP):
New faux prompt, as seen in IE7 (WinXP)

Important note: The IE7 modal window will forcibly display the address and status bars if being called by a server (not localhost) which isn’t listed in that user’s list of ‘Trusted Sites.’ This is annoying, but still better than having no prompt() at all. IE6 forcibly displays the status bar, but not the address bar.

Example

Before I dig into the code, here’s a functioning example. There are two files involved in this hack: the main HTML page calling the prompt, and the faux prompt HTML page.

The traditional prompt()

For those of you new to using prompts, here’s an example of a traditional prompt in action:


window.onload = function (){
   var name = prompt("Please enter your name", "");
   if(name){
      alert("You entered '" +name +"'.");
   }
}

Return values

A key feature of prompt() is that it returns the value of the textfield as a string. If nothing was typed into the text field, prompt() returns either null or false, depending on your browser. If the user clicks ‘cancel’, prompt() returns false.

Our faux prompt for IE needs to work the same way. As luck would have it, showModalWindow allows us to specify return values.

Prompt text

Another key feature of prompt() is the ability to display your own text in the prompt, such as “Please enter your name.” To make our lives easier, our faux prompt should work the same way, using the same syntax.

Our IE-specific function: iePrompt()

In all its glory:


function iePrompt(str){
   var settings = "dialogWidth: 290px; dialogHeight: 160px; center: yes; edge: raised; scroll: no; status: no;";
   return window.showModalDialog("iePrompt.html", str, settings);
}

Let’s break it down.


function iePrompt(str){

Since we can’t use the traditional prompt(), we need to create a new, similar function. Just as prompt allows you to specify what text will display by passing a string,

prompt("This text will display in my prompt","")

we want to be able to pass a string in our new function:

iePrompt("This text will display in my prompt")


var settings = "dialogWidth: 290px; dialogHeight: 160px; center: yes; edge: raised; scroll: no; status: no;";

IE’s showModalDialog allows you to style the window much like a pop-up window. The settings are entered as a single string. For convenience and readability, I placed all the settings in a variable named “settings”. You can tweak these settings to suit your own needs. A list of optional parameters can be found here.

Important note: The height of the modal window is set here using dialogHeight; if the display text (in this case “Please enter your name”) wraps to the next line, the window will NOT expand to fit it. If you’re working with long strings, you’ll need to test the height of your modal window, or develop your own sizing routine. Also note that in IE6, dialogHeight referred to the height of the entire dialog window. In IE7, the model was changed, and dialogHeight now refers ONLY to the height of the content. See this IEBlog for more info.

return window.showModalDialog("iePrompt.html", str, settings);

As mentioned earlier, showModalWindow can return a value the same way prompt() returns a value. We want our iePrompt() function to pass the value returned by showModalWindow.

  • iePrompt.html is the name/path of the HTML file containing a form that mimics prompt().
  • str is the text that will be displayed in the prompt.
  • settings is the variable containing the settings string we defined earlier.

The iePrompt.html file

I don’t want to spend too much time explaining the HTML file, as it’s a simple HTML file containing a wee bit of CSS for styling, and a very tiny form. There are some important elements to note, though.

The submit function


function formSubmit(){
   var str = document.getElementById("promptText").value;
   if(str){  
      window.returnValue = str;
   } else {  
      window.returnValue = false;
   }
   window.close();
}

In order to get the showModalDialog function to return a value, we have to make our form return a value. To do this, we have to specifically use window.returnValue. The code is set up to conditionally send either the content of the promptText field, or the value false, just like a normal prompt.

After returning the value to the page that called the prompt, we need to close the modal window by calling window.close.


function formCancel(){
   window.returnValue = false;
   window.close();
}

Prompts also have cancel buttons. We want our modal window to have a cancel button that behaves just like a prompt. To do this, we set up a function that returns the value false and closes the modal window.


window.onload = function (){
   var str = window.dialogArguments;
   if(str){
      document.getElementsByTagName("label")[0].innerHTML = str;
   }
}

This bit of code grabs the display text value being passed by iePrompt and dynamically inserts it into a label on our form. We’re passing the argument using the dialogArguments property of the modal window generated by showModalDialog.


<body onbeforeunload="formCancel();">

Lastly, we need to take into account the fact that many people choose to click the dialog window’s close button (X) instead of OK or Cancel. Using onbeforeunload allows us to call formCancel() if the user decides to close the window.

And that’s it! We now have a functioning prompt for IE.

Putting it into action

Now that we have our custom IE prompt, we need to integrate it with non-IE browsers. Fortunately, this is a pretty simple task.

Determining if the browser is IE

Rather than use some elaborate browser-sniffing technique, we’ll stick to supported feature detection, which is considered a best-practice by the DOM scripting crowd. This is easily accomplished by checking for window.showModalDialog. If the return value is true, the browser is a flavor of Internet Explorer (v4 and higher), and supports our new prompt method. If the return value is false, the browser isn’t IE and should be able to use a traditional prompt().


function cbPrompt(str){
   try {
      if(window.showModalDialog){ return iePrompt(str); }
         else { return prompt(str, ""); }
   } catch (e) { 
         return false; 
   } 	
}

I decided to use a try/catch statement for future expandability (being able to add extra functionality, such as using confirm() to validate the text entered by the user. You could rewrite it to use simple if/else statements.

I wrapped the logic into a new function called cbPrompt (“cb” meaning cross-browser). Now anytime I need a prompt, I simply call cbPrompt instead of prompt():


window.onload = function (){
   var name = cbPrompt("Please enter your name");
   if(name){
      alert("You entered '" +name +"'.");
   }
}

As you can see, it’s almost exactly the same as using the traditional prompt:


window.onload = function (){
   var name = prompt("Please enter your name", "");
   if(name){
      alert("You entered '" +name +"'.");
   }
}

Just remember that you have to ensure the iePrompt.html file is present and that the path defined in the iePrompt function is accurate.

Here’s a fully-functional cross-browser example.