Tuesday, June 17, 2008

Dynamic text field prompts with Javascript

Edit: (2 Sep 2008), explained why IE doesn't like the first example.

The problem: the client wants a username and password field, but space is too tight to allow for labels. Instead, they want the labels inside the fields. The labels should disappear once the user puts their cursor inside the field. Let's call them prompts from here on in because they are not permanent.

Here is my first attempt.

It works ok in Firefox 2, but not in IE 6. :(

The password field is the problem. The Javascript dynamically toggles the password field's type between text and password via password.type = "text" and password.type = "password". IE doesn't allow this action. No error is raised, it just ignores it.

Here is the code.

<script language="javascript" type="text/javascript">
<!--
  // Clear prompt from username field, if required.
  function clearUsernamePrompt() {
    var username = document.getElementById("username2");
    if (username.value == "Username") {
      username.value = "";
    }
  }

  // Set the prompt for the username field, if required.
  function setUsernamePrompt() {
    var username = document.getElementById("username2");
    if (username.value == "") {
      username.value = "Username";
    }
  }

  // Clear prompt from password field, if required.
  function clearPasswordPrompt() {
    var password = document.getElementById("password2");
    if (password.value == "Password") {
      password.type = "password";
      password.value = "";
    }
  }

  // Set the prompt for the password field, if required.
  function setPasswordPrompt() {
    var password = document.getElementById("password2");
    if (password.value == "") {
      password.type = "text";
      password.value = "Password";
    }
  }
// -->
</script>

<input type="input" value="Username" id="username2"
    onFocus="clearUsernamePrompt();" onBlur="setUsernamePrompt();"/>
<input type="input" value="Password" id="password2" value="Password"
    onBlur="setPasswordPrompt();" onFocus="clearPasswordPrompt();"/>

An alternative approach is to use two fields for the password: one is a text input and the other is a password. Now we use the handlers to change which one is visible. Here is the second attempt.

And here is the code.

<script language="javascript" type="text/javascript">
<!--
  // Clear prompt from username field, if required.
  function clearUsernamePrompt() {
    var username = document.getElementById("username");
    if (username.value == "Username") {
      username.value = "";
    }
  }

  // Set the prompt for the username field, if required.
  function setUsernamePrompt() {
    var username = document.getElementById("username");
    if (username.value == "") {
      username.value = "Username";
    }
  }

  // Clear prompt from password field, if required.
  function clearPasswordPrompt() {
    var password = document.getElementById("password");
    password.style.display = "inline";
    password.focus();
    var passwordPrompt = document.getElementById("passwordPrompt");
    passwordPrompt.style.display = "none";
  }

  // Set the prompt for the password field, if required.
  function setPasswordPrompt() {
    var password = document.getElementById("password");
    if (password.value == "") {
      password.style.display = "none";
      var passwordPrompt = document.getElementById("passwordPrompt");
      passwordPrompt.style.display = "inline";
    }
  }
// -->
</script>
<input type="input" value="Username" id="username"
    onFocus="clearUsernamePrompt();" onBlur="setUsernamePrompt();"/>
<input type="password" id="password" style="display:none"
    onBlur="setPasswordPrompt();" /><input type="text" value="Password"
    id="passwordPrompt" onFocus="clearPasswordPrompt();"/>

Note 1. Make sure there is no space in between the password and passwordPrompt fields. If you leave any space there, the transition will look odd - the password field will look like it is jumping.

Note 2. As always, you must take careful consideration of your target audience. Specifically relevant to this example: will they always have Javascript enabled? If they don't, this page won't work - they will never be able enter a password! For the majority of websites nowadays, it is an assumption that Javascript will always be enabled, especially for the "Web 2.0" sites, but you need to be sure before you use this.

Another alternative would be to use DOM within the Javascript to swap elements in and out. This would work and might even make the HTML look simpler, but has a major complication: swapping fields in and out will disturb the tab order. Unless you explicitly set tab indexes (for all the fields on the form), DOM manipulation can screw that up.