Designing Modern Web Forms with HTML 5 and CSS3

Recently I noticed that many web developers are still using HTML tables to layout their forms. Mainly it is because people stick with what they know, and have never taken the time to learn a better way. Once you learn to layout forms with standards compliant CSS it is actually quite easy!

View Demo Download Code

We will be using HTML5 and CSS3 to achieve great style and functionality without causing problems in less capable browsers. To be clear, this code will not look exactly the same in every browser. We are designing for the most advanced browsers, then making sure it still degrades gracefully.

Starting with the right markup.

Here we are using HTML 5 to code the form. Take a look:

<div id="registration">
<h2>Create an Account</h2>

<form id="RegisterUserForm" action="" method="post">
<label for="name">Name</label>
<input id="name" name="name" type="text" class="text" value="" />

<label for="tel">Phone Number</label>
<input id="tel" name="tel" type="tel" class="text" value="" />

<label for="email">Email</label>
<input id="email" name="email" type="email" class="text" value="" />

<label for="password">Password</label>
<input id="password" name="password" class="text" type="password" />

<p><input id="acceptTerms" name="acceptTerms" type="checkbox" />
<label for="acceptTerms">
I agree to the <a href="">Terms and Conditions</a> and <a href="">Privacy Policy</a>

<button id="registerNew" type="submit">Register</button>



Note the input types. Instead of only using the usual “name” and “password” I also added “tel” and “email”. Most browsers don’t render anything different here, but it makes a big difference for the user experience on Safari mobile (iPhone and iPad). The key difference is a rearranged keyboard to focus on the type of input. Email adds the @ sign as well as a . button. Also the auto-correct changes so it doesn’t try to split domain names into multiple words.

It looks like a minor difference but it is very frustrating to enter an email address into a text input on the iPhone. Your users will thank you for paying attention to the details.

Older browsers that don’t understand HTML 5 forms will just fall back to input type=”text”. Which is just fine for our purposes. Also each field has class of “text” so that I can style them with the CSS input.text selector. Even though they aren’t all text fields, I do want them to look the same. You could use CSS3 selectors instead, but getting that to work in IE is beyond the scope of this article.

Adding basic styling.

Now to style our form. We are going to start with a very simple reset. Please use something more appropriate to your project.


/* Add whatever you need to your CSS reset */
html, body, h1, form, fieldset, input {
margin: 0;
padding: 0;
border: none;

body { font-family: Helvetica, Arial, sans-serif; font-size: 12px; }


Now to style the form container.


#registration {
color: #fff;
background: #2d2d2d;
background: -webkit-gradient(
left bottom,
left top,
color-stop(0, rgb(60,60,60)),
color-stop(0.74, rgb(43,43,43)),
color-stop(1, rgb(60,60,60))
background: -moz-linear-gradient(
center bottom,
rgb(60,60,60) 0%,
rgb(43,43,43) 74%,
rgb(60,60,60) 100%
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
margin: 10px;
width: 430px;

#registration a {
color: #8c910b;
text-shadow: 0px -1px 0px #000;

#registration fieldset {
padding: 20px;


Here we are using CSS3 gradients to set the background of the container. We are using three different background declarations to accommodate different browsers. First we set a background color of #2d2d2d that all browsers will understand, then we overwrite it for -webkit and -moz to use background gradients instead. Since Internet Explorer doesn’t understand gradients it will ignore them and use the solid color specified first.

You can use this website to generate your own CSS gradients.

Then for the rounded corners we are adding -webkit-border-radius, then -moz-border-radius for the browsers that support it, then adding standard border-radius for when the official spec is adopted in the future (hopefully by IE9).

For the links we are adding a default color, then more importantly adding text-shadow (not supported in IE). The syntax for the text-shadow is this:


text-shadow: x  y  blur  color;



text-shadow: 0px -1px 0px #000;


So we are using that to add a black vertical shadow that gives the text an indented look.

Styling the Input Fields


input.text {
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
border:solid 1px #444;
font-size: 14px;
width: 90%;
padding: 7px 8px 7px 8px;
background: #ddd;
background: -moz-linear-gradient(
center bottom,
rgb(225,225,225) 0%,
rgb(215,215,215) 54%,
rgb(173,173,173) 100%
background: -webkit-gradient(
left bottom,
left top,
color-stop(0, rgb(225,225,225)),
color-stop(0.54, rgb(215,215,215)),
color-stop(1, rgb(173,173,173))
text-shadow:0px 1px 0px #FFF;
-moz-box-shadow: 0px 1px 0px #777;
-webkit-box-shadow: 0px 1px 0px #777;
box-shadow: 0px 1px 0px #777;


Here we are adding background gradients again, remember to specify the default for older browsers. The rounded corners also give the fields a nice pill shape.

The new part is that we used a box-shadow to give it a recessed look. The syntax is the same for box-shadow as it is for text-shadow. So box-shadow: 0px 1px 0px #777; is a light colored shadow, with no blur, that is down 1px. This combined with a dark stroke gives it the look below.

Adding Icons.

Next we will add icons to each field so that it is more easily identified at a glance. With CSS3 we are able to use multiple backgrounds to have both a gradient and an image. First create a sprite image of all your icons combined into one file. This will decrease HTTP requests, simplify your markup, and improve page load. An example of the icons I used are on the right.

You will want to replace the earlier code for the input field backgrounds with this new code.


background: #ddd url(‘img/inputSprite.png’) no-repeat 4px 6px;
background: url(‘img/inputSprite.png’) no-repeat 4px 6px, -moz-linear-gradient(
center bottom,
rgb(225,225,225) 0%,
rgb(215,215,215) 54%,
rgb(173,173,173) 100%
background:  url(‘img/inputSprite.png’) no-repeat 4px 6px, -webkit-gradient(
left bottom,
left top,
color-stop(0, rgb(225,225,225)),
color-stop(0.54, rgb(215,215,215)),
color-stop(1, rgb(173,173,173))


We are able to add multiple backgrounds by separating each one with a comma. To accommodate the new icons we will also need to change the right padding to 30px.

padding: 7px 8px 7px 30px;

Then specify the background position for each field individually so that it will display the correct icon. The exact values will depend on the icons that you use. Note that the order of the icons in the sprite does not have to match the order of the input fields.


input#email {
background-position: 4px 5px;
background-position: 4px 5px, 0px 0px;
input#password {
background-position: 4px -20px;
background-position: 4px -20px, 0px 0px;
input#name {
background-position: 4px -46px;
background-position: 4px -46px, 0px 0px;
input#tel {
background-position: 4px -76px;
background-position: 4px -76px, 0px 0px;


Here the first background-position is for the browsers that don’t support multiple background images, the second is for the gradient position on the browsers that do support it.

Styling the Header & Submit Button


#registration h2 {
color: #fff;
text-shadow: 0px -1px 0px #000;
text-align: center;
padding: 18px;
margin: 0px;
font-weight: normal;
font-size: 24px;
font-family: Lucida Grande, Helvetica, Arial, sans-serif;
border-bottom: solid #181818 1px;
-moz-box-shadow: 0px 1px 0px #3a3a3a;
-webkit-box-shadow: 0px 1px 0px #3a3a3a;
box-shadow: 0px 1px 0px #3a3a3a;


Using a bottom border and a box shadow we are able to create an indented separating line without any additional markup.

For the submit button we will use an sprite that has 3 states for :link, :hover, and :active.

You can then use different background positions to shift the image up for each state. This keeps your HTTP requests to a minimum and also prevents a flicker while the browser loads an image for the :hover state.


#registerNew {
width: 203px;
height: 40px;
border: none;
text-indent: -9999px;
background: url(‘img/createAccountButton.png’) no-repeat;
cursor: pointer;
float: right;
#registerNew:hover { background-position: 0px -41px; }
#registerNew:active { background-position: 0px -82px; }


Moving Labels Inline with jQuery.

To further style the forms I want to move the label inside the field itself. This technique is largely based on the work from Trevor Davis at Viget Labs.


<script type="text/javascript">

$(document).ready(function() {
* In-Field Label jQuery Plugin
* Copyright (c) 2009 Doug Neiner
* Dual licensed under the MIT and GPL licenses.
* Uses the same license as jQuery, see:
* @version 0.1
(function($) { $.InFieldLabels = function(label, field, options) { var base = this; base.$label = $(label); base.$field = $(field); base.$"InFieldLabels", base); base.showing = true; base.init = function() { base.options = $.extend({}, $.InFieldLabels.defaultOptions, options); base.$label.css(‘position’, ‘absolute’); var fieldPosition = base.$field.position(); base.$label.css({ ‘left': fieldPosition.left, ‘top': }).addClass(base.options.labelClass); if (base.$field.val() != "") { base.$label.hide(); base.showing = false; }; base.$field.focus(function() { base.fadeOnFocus(); }).blur(function() { base.checkForEmpty(true); }).bind(‘keydown.infieldlabel’, function(e) { base.hideOnChange(e); }).change(function(e) { base.checkForEmpty(); }).bind(‘onPropertyChange’, function() { base.checkForEmpty(); }); }; base.fadeOnFocus = function() { if (base.showing) { base.setOpacity(base.options.fadeOpacity); }; }; base.setOpacity = function(opacity) { base.$label.stop().animate({ opacity: opacity }, base.options.fadeDuration); base.showing = (opacity > 0.0); }; base.checkForEmpty = function(blur) { if (base.$field.val() == "") { base.prepForShow(); base.setOpacity(blur ? 1.0 : base.options.fadeOpacity); } else { base.setOpacity(0.0); }; }; base.prepForShow = function(e) { if (!base.showing) { base.$label.css({ opacity: 0.0 }).show(); base.$field.bind(‘keydown.infieldlabel’, function(e) { base.hideOnChange(e); }); }; }; base.hideOnChange = function(e) { if ((e.keyCode == 16) || (e.keyCode == 9)) return; if (base.showing) { base.$label.hide(); base.showing = false; }; base.$field.unbind(‘keydown.infieldlabel’); }; base.init(); }; $.InFieldLabels.defaultOptions = { fadeOpacity: 0.5, fadeDuration: 300, labelClass: ‘infield’ }; $.fn.inFieldLabels = function(options) { return this.each(function() { var for_attr = $(this).attr(‘for’); if (!for_attr) return; var $field = $("input#" + for_attr + "[type=’text’]," + "input#" + for_attr + "[type=’password’]," + "input#" + for_attr + "[type=’tel’]," + "input#" + for_attr + "[type=’email’]," + "textarea#" + for_attr); if ($field.length == 0) return; (new $.InFieldLabels(this, $field[0], options)); }); }; })(jQuery);

$("#RegisterUserForm label").inFieldLabels();



The line “$(“#RegisterUserForm label”).inFieldLabels();” is what activates the script for those particular labels. Make sure to change the ID if yours is different. I modified the script to add support for the input types “tel” and “email”. If you choose to use others you will need to write those in (near the end of the script).

We are also adding a class of .infield to the labels that need to be restyled. This way if JavaScript is disabled the form will degrade gracefully. Here is the necessary CSS:


fieldset label.infield /* .infield label added by JS */ {
color: #333;
text-shadow: 0px 1px 0px #fff;
position: absolute;
text-align: left;
top: 3px !important;
left: 35px !important;
line-height: 29px;

Sometimes the browser auto-complete can interfere with the inline form fields (especially on login boxes). If this is an issue for your site then you can add autocomplete=”off” to the input fields.

Note: We could have used the HTML5 Placeholder attribute instead, but this method works better in older browsers and also I like how it looks better.

How it looks in Internet Explorer

Because we designed first for modern browsers, certain less capable browsers will not be able to display the form in its best possible look. Here is what IE users will see:

Not as pretty, but everything still functions perfectly.

That’s all!

Please ask any questions and give feedback in the comments.

View Demo Download Code

How We Switched Twitter Usernames

A big part of changing names from WP Limits to Legend Themes was switching the Twitter account. I am never sure how much of a connection your Twitter followers actually have with a specific account. Would they notice if an account suddenly switched names? How much notice should you give?

Acquiring the New Name.

Once deciding on a new domain name I set out to find a Twitter username. It was quite surprising that the domain name was available, but @LegendThemes was not. Luckily I was able to contact the owner and negotiate a reasonable purchase price of $60. Because a Twitter account is free at first it seemed very foreign to pay for it (my wife’s response was “You paid how much for something that is normally free?”), but I think having the right name (especially at that price) is definitely worth it.

Have a Backup Option.

While I wasn’t sure if I could get @LegendThemes I checked every variation and @ThemeLegend was the only acceptable option available. This was quick to save by creating a new twitter account. I waited to announce anything on Twitter until I found out if I could buy my preferred choice.

Once I had the login information for the new account (after paying for it, of course) I made sure to change the email address and password, so that the account was fully in my control. Since Twitters password recovery option is through email it is very important that you change the email address.

Making the Switch.

On the @WPlimits account I made several posts, before and after, to let followers know I would be switching it over to the new name. Wait a while to give anyone time to respond. Then go into the newly purchased account and change the username. I just change it to @legendthemes2, then logged back into @wplimits and changed it to @LegendThemes. Simple.

Technically someone could have stolen the account for the 30 seconds it was exposed, but they would a) have to care about it, and b) know exactly when I was making the switch. Not much of a concern.

From there update the profile image and change the background (if needed), and the important part is done!

Final Details.

Because I didn’t want to lose any users and wanted to minimize any confusion I setup a new account at the now available @WPlimits which pointed to @LegendThemes. I also updated the @ThemeLegend profile to point users in the correct direction as well. The point is to just tie up any possible loose ends.

Have you ever had to switch Twitter usernames? Share your story or thoughts in the comments.

Renamed and Rebranded

Over the past few weeks I have become more and more frustrated with the name “WP Limits”. The original idea a couple years ago was that I would write a blog that featured ideas on how to push the limits of WordPress, hence the name WP Limits (it made sense at the time).

Since then I didn’t blog as much as I would have liked, but did build up a reasonable Twitter following, and some traffic to the site. Since deciding to move into WordPress theme development I have felt the need for a new name that is easier to pronounce (the WP part trips off the tongue), more memorable, and most importantly, easier to brand.

So, with pleasure, I am introducing Legend. Or Legend Themes, as it will probably be more commonly known.

The logistics of the switch.

  • Company Names. I threw out a lot of ideas that I thought were good, but ultimately not great.
  • Domain Names. It is so frustrating how many good domain names are taken, but not actually used. The iPhone app Domain Scout was very handy for quickly checking if a name would work.
  • Twitter User names. Several options for good domain names didn’t have an open Twitter account. One that I really wanted hadn’t been used since 2007, and the owner didn’t respond to any contact attempts. Does anyone know if Twitter has a policy on removing old accounts?
  • The Re-design. It actually went very quickly. Once I had the name I ran through a couple quick concepts, settled on the one you see now, and had it coded within a few hours (I used the Refresh theme as a starting point, so coding was very fast).
  • Moving. The actual painful part was switching the site, old blog posts, theme demos, and everything else over to the new name and domain. It was mostly just tedious busy work. Though I am very glad I made the switch early, as it would have been twice as hard in another couple months.

Note: Sometime in the next few days the Twitter account @WPlimits will be switched to become @ThemeLegend @LegendThemes. I hope to give plenty of warning before hand so it isn’t too confusing.

What do you think?

Do you think I made the right choice in renaming the company?

Refresh Your Site

Here’s a preview of our next theme coming up. We have been working on it for the last two weeks. It includes great support for WordPress 2.9 custom post thumbnails, a jQuery powered image and post slider on the homepage, as well as great widget support!

Take a look at Refresh.

The Details.

You can choose a color scheme, add in a custom heading, and choose a category of posts to feature in the home page rotator. Take a look at the starting color schemes:

If you have requests for additional color schemes or features let us know. Stay tuned for this theme to be released within the next week!

Top Sites for WordPress Information

This is the series of sites that I subscribe to in order to keep up on WordPress news and to always get better at working with WordPress.

WordPress Development & Announcements

  • Official WordPress Blog
    Jane Wells provides great updates on the development status, any new features being released, and also where you can jump in to help the project.
  • WordPress UI
    The WordPress UI group works here to discuss improvements to the software that are user interface related. You can get involved with the UI IRC chat on Thursdays at 2:00 PM Eastern.
  • WordPress Dev
    From here you can follow the status of the latest WordPress development projects. You can get involved with the main WordPress development IRC chat on Thursdays at 3:30 PM Eastern.
  • Matt’s Blog
    The founders blog is always a good place to stay up on WordPress announcements, plus he is a very interesting entrepreneur.
    The official site & forums for BuddyPress development. If you aren’t already using BuddyPress for a project you should be as it no longer requires an installation of WordPress MU.

Tips & Tutorials

  • Smashing Magazine on WordPress
    Smashing always puts out high quality articles and their WordPress posts are no exception.
  • NetTuts on WordPress
    Envato has a great section on working with WordPress, not updated too often, but definitely worth subscribing too.
  • WP Engineer
    Here you can get more technical tips as well as great previews for what is coming in the next version of WordPress.
  • WP Recipes
    Jean-Baptiste Jung’s blog on WordPress tips and tricks. He has some of the best simple tips to help you customize your WordPress blog.
  • Justin Tadlock
    I learned all about custom taxonomies and other great ideas from Justin. His blog is a must read for an advanced WordPress developer.
  • WP Candy
    This site hasn’t been updated lately, which is a shame, because their old content is really good and helpful.
  • Theme Shaper
    Ian Stewart is the creator of the Thematic framework and the Kirby theme which is the foundation of the new WordPress default theme 2010. His blog is great for tips and WordPress news.

WordPress MU

    Though mostly focused on WordPress MU, they have recently branched out to standard WP tips as well as lots of great resources on BuddyPress.
  • WPMU Tutorials
    Andrea and Ron are two of the most helpful members of the WordPress community. Their blog on WordPress multi-user is a must read!

There are many more WordPress tutorial sites out on the web that I didn’t list here. This is just the collection that I find valuable on a day-to-day basis. If you have suggestions of sites I should add let me know in the comments.

Our blog will regularly be updated with WordPress tips, theme announcements, and general news. Subscribe to our RSS feed to stay updated.

Announcing: WordPress Theme Store

I am very pleased to announce that WP Limits is launching a  WordPress theme store. Over the past couple of months we have been working hard to design and develop a great set of themes to kick start this new venture.

Our Themes

Here are the great themes we are launching with:

  • Dynamic Business
    A CMS theme designed to help you easily create business sites.
  • Knowledge
    Knowledge turns WordPress into a knowledge base or wiki site.
  • Emphasis
    A free blogging theme with an emphasis on content.

Expect a new theme to be released every 2-3 weeks, with teaser the week before a release. Of course our themes are all released under the GPL license so you are free to modify and distribute as you please.

General Questions

Why another theme store?

WP Limits has been known in the community for over a year for pushing the limits of what is possible with WordPress, now the idea is to take that knowledge into the theme market. More friendly competition will mean that theme quality will continue to go up and more innovation will take place. I am looking forward to seeing what we can contribute to the community over the next several years.

What about support?

To start out to get support for our themes you can visit our support page. In the near future we will be adding support forums and user accounts.

How do we maintain quality?

We have a team of beta testers who review each of our themes before launch. If issues do come up we are fix them promptly and updated themes will be available for download. If you have suggestions for how we can improve our themes please let us know.

View our Themes »

Our blog will regularly be updated with WordPress tips, theme announcements, and general news. Subscribe to our RSS feed to stay updated.

Update: On March 24th, 2010 WP Limits was renamed to Legend Themes.

Beta Testers Needed

Interested in getting copies of cutting edge premium themes before they are released to the public? We are putting together a small team of insiders to help us plan & test new WordPress themes. See below for details!

[gravityform id=1 name=WordPressTheme Beta Testers]

Emphasis Theme Preview: Design Critique

I finally got around to designing a new theme to giveaway to the WordPress community. Before writing the code I would like to get some input from the community on the design, as well as what features you would like to see included. Click on each image for the full-size version.


  • Focus on Content
  • Clean, effective design
  • Author Comment Highlighting
  • Widgetized Sidebar

Here is the home page:


Here is a post page (single.php):


Do you have any constructive feedback on the design and layout? If you were to use this theme on your blog what features would you like to see?

It’s Official: We’ll Design Your WordPress Site!

We just launched the WP LImits custom themes page, which I am happy to say has been well received by our Twitter friends who got to preview it (follow us @wplimits). So we are now open for business!

Since WordPress can be used to create a full website, not just a blog, we wanted to make great CMS-like, custom themes available at an affordable price. And to kick it off we are offering a discount to $1,200 USD.

WP Limits Custom WordPress Theme Designs
WP Limits Custom WordPress Theme Designs

If you would like to see more of our work you can take a look at our web design studio in Boise where all of our great designs come from!