Part 2: Building a Unique Contact Form

Avatar of Chris Coyier
Chris Coyier on (Updated on )

I’m calling this Part 2, because last week I began this adventure over on Tutorial Blog where we first designed a unique contact form:

Photoshopping a Unique Contact Form

Here we are going to pick up where that left off and actually build this thing with HTML/CSS, as well as add some validation with jQuery, and make it tick with PHP. Here is what we are building:



1. Slicing out images from Photoshop

The big background image (everything except the form elements)

The page background texture (for everywhere else)

The send button

The input area backgrounds. To create this, I cropped down around the area, exported, then changed the “color overlay” layer style on that layer and exported again. Then I opened both of those exported file, placed one on top of each other, and exported again.

The textarea background. Same technique as above.


2. Marking up the form

This is a typical <form> in most ways. Some labels and inputs with a submit button at the end. What is different about it is the Left and Right divs we need to include because this is essentially a two-column form. Also, each input is wrapped in a div, as we need a hook to properly apply the background images we created.

Here is the all the markup:

<div id="page-wrap">

	<form method="post" action="contactengine.php" id="commentForm">

		<div id="formLeft">
			<label for="Name">Name:</label>
			<div class="input-bg">
				<input type="text" id="Name" name="Name" class="required" minlength="2" />
			<label for="City">City:</label>
			<div class="input-bg">
				<input type="text" id="City" name="City" class="required" minlength="2" />
			<label for="Email">Email:</label>
			<div class="input-bg">
				<input type="text" id="Email" name="Email" class="required email" />
		<div id="formRight">
			<label for="Message">Message:</label></td>
			<div class="message-bg">
				<textarea name="Message" id="Message" rows="20" cols="20" class="required"></textarea>
			<br />
			<input type="image" src="images/send-button.jpg" name="submit" value="Submit" class="submit-button" />

		<div class="clear"></div>




3. Styling with CSS

I’m not going to explain every attribute, as I think much of this is pretty simple and self-explanatory. First I’ll show the code here, then I’ll explain a few of the highlights/less obvious stuff below.

* { margin: 0; padding: 0; }
body { font-size: 62.5%; font-family: Georgia, serif; background: url(images/page-bg.jpg); }
.clear { clear: both; }
fieldset { border: none; }

#page-wrap {
	width: 800px;
	margin: 0 auto;
	background: url(images/form-bg.jpg) top center no-repeat;
	min-height: 600px;
form {
	padding: 83px 0 0 76px;
h1 {
	text-align: center;
	padding-top: 200px;
#formLeft {
	width: 320px;
	float: left;
	#formLeft input {
		width: 250px;
		margin: 0 0 20px 0;
		border: none;
		text-align: center;
		background: none;
		margin: 13px 0 0 8px;
		font-size: 1.4em;
	#formLeft .input-bg {
		background: url(images/form-sm-bg.jpg) bottom left no-repeat transparent;
		height: 45px;
		margin-bottom: 10px;
		position: relative;
	#formLeft .active {
		background: url(images/form-sm-bg.jpg) top left no-repeat transparent;
#formRight {
	width: 360px;
	float: right;
	padding-right: 44px;
	#formRight textarea {
		width: 298px;
		height: 209px;
		display: block;
		border: none;
		background: none;
		margin: 0 0 0 20px;
		padding: 13px 0 13px 0;
		font-family: Helvetica, sans-serif;
		font-size: 1.3em;
	#formRight .message-bg {
		background: url(images/message-bg.jpg) bottom left no-repeat transparent;
		height: 238px;
	#formRight .active {
		background: url(images/message-bg.jpg) top left no-repeat transparent;
label {
	display: block;
	font-size: 1.3em;
	text-indent: 10px;
	font-weight: bold;
label.error {
	position: absolute;
	top: -16px;
	right: 49px;
	padding: 3px;
	color: #da3939;
	font-size: 1.0em;
	text-align: right;
	font-style: italic;
	font-weight: normal;
input.submit-button {
	float: right;
	padding-right: 31px;

Notice I’m using the * selector here even though I am using forms. The * selector and forms only don’t get along when you apply border: none; there, which wrecks default styling for submit buttons and things. We are already going to do a good job of wrecking default styling, so so be it =)

Remember those hooks we threw in to wrap the inputs? We apply the background image to those hooks rather than the input itself. Inputs don’t like background images. We also created an “active” class for the inputs, where the background image is shifted from bottom left to top left. Applying and removing that class is what will create our current field highlighting we will cover later.

Each of these extra hooks also has relative positioning. That is because of the “error” messaging that is going to be dynamically added to the page during the form validation. To get those messages positioned correctly, they are going to be absolutely positioned within those relatively positioned parents.

One thing that we didn’t do here is apply a background image to the submit button. You get better cross-browser results by making your submit button of type=”image” and giving it a src image rather than of type=”submit” and applying a background image.


4. Current Field Highlighting with jQuery

Partially for good usability and partially for good aesthetics, we are going to implement current field highlighting. That is why we created those form background images with two different colors. CSS provides some support for this with it’s :focus pseudo class, but that won’t help us for two reasons. One, it only works on form elements, and we need to change styling of the parent element of the form element which is not possible with CSS. Two, the :focus class isn’t widely supported.

We will use jQuery for this, since it supports all the event types that we need: hover, focus and blur. The desired effect is that when any of these form elements are moused over, the background image of the parent element swaps out to our alternate version indicating it is the current field.

Since we have two different types of elements we wish to do this for, we’ll need to write two seperate but very similar chunks of jQuery:

<script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
<script type="text/javascript">
	$("#formLeft .input-bg").hover(function() {
	}, function() {
	$("#formLeft input").focus(function() {
	$("#formLeft input").blur(function() {
		$("#formLeft .input-bg").removeClass("active");
	$("#formRight .message-bg").hover(function() {
	}, function() {
	$("#formRight textarea").focus(function() {
	$("#formRight textarea").blur(function() {
		$("#formRight .message-bg").removeClass("active");

That probably looks more complicated than it is… all this is doing is adding and removing the class of “active” from the appropriate elements when different events occur. This makes the current field highlighting work on a mouse rollover, as well as when the inputs are tabbed to.

More on current field highlighting here.


5. Validating the form

Form validation is useful for both the sending and receiving parties of a contact form. For the sender, it makes sure they have done things like provide a valid email address. Chances are good that if they are using a contact form they wouldn’t mind being contacted back, so this is an effort to make sure that field is filled out correctly. For the receiver, form validation is a good start in protection against spam. Also, more directly, it ensures that all submissions have the information that has been declared most important.

Since we are already using the almighty jQuery, let’s use it to handle our form validation right on the client side. Fortunately, there is a great plugin for this already built. Simply include the script on your page (after the main jQuery library of course) and add validation to your form by referencing it by ID:

<script type="text/javascript" src="js/jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="js/jquery.validate.js"></script>
<script type="text/javascript">

This plugin is looking for specific class names (and in some cases other attributes) from your inputs to do it’s validation. For instance, we want our “Name” field to be a required field, and that the value is greater than or equal to two characters in length. Just add two new attributes to our input element: class=”required” and minlength=”2″.

<input type="text" name="Name" class="required" minlength="2" />

For email address validation, just add the class name like so:

<input type="text" name="Email" class="required email" />

For more advanced and different types of validation, see the documentation for the plugin.


6. Making it work with PHP

Our form validation will prevent the submit button from triggering the “action” of our form if any of the fields don’t pass muster. But if all the fields are valid, we want our for to actually do something, right? Since this is a contact form, what we want to happen is for an email to be generated and sent to a specified email address.

In our markup, the “action” for our form is declared here:

<form method="post" action="contactengine.php" id="commentForm">

This will call the “contactengine.php” file and send it variables from our form as POST variables. It is our job then, to capture these variables, create a formated email of of them, and blast off the email.

Here is how that is done. This is the entire contents of the contactengine.php file:



$EmailFrom = "[email protected]";
$EmailTo = "[email protected]";
$Subject = "Contact Form Submission";

$Name = Trim(stripslashes($_POST['Name'])); 
$Tel = Trim(stripslashes($_POST['Tel'])); 
$Email = Trim(stripslashes($_POST['Email'])); 
$Message = Trim(stripslashes($_POST['Message'])); 

// prepare email body text
$Body = "";
$Body .= "Name: ";
$Body .= $Name;
$Body .= "\n";
$Body .= "Tel: ";
$Body .= $Tel;
$Body .= "\n";
$Body .= "Email: ";
$Body .= $Email;
$Body .= "\n";
$Body .= "Message: ";
$Body .= $Message;
$Body .= "\n";

// send email 
$success = mail($EmailTo, $Subject, $Body, "From: <$EmailFrom>");

// redirect to success page
if ($success){
  print "<meta http-equiv="refresh" content="0;URL=contactthanks.html">";
  print "<meta http-equiv="refresh" content="0;URL=error.html">";

The meat of this is the “mail” function, which actually does the sending of the email. Notice we call it by while setting a variable ($success). This variable will tell us if the mail was sent successfully or not. If TRUE, we can redirect to our “thank you” page. Otherwise, we should let the user know something went wrong and redirect to an error page.


Demo & Download

So there you have it folks! A nice looking and fully functional form.

View Demo
(Don’t try to actually contact me through this form. If you need to contact me, use my regular contact form).

(Includes Photoshop File)



Safari likes to apply it’s glowy blue border around all text inputs and text areas. At the time of this writing, there is no way to fight it. This doesn’t ruin the usability of the form at all, it just looks a little strange with this design. UPDATE: gaga pointed out below setting outline: none on these form elements will eliminate the Safari glowy blue border. Did not know that, thanks!

IE & Opera like to put vertical scrollbars on textareas no matter what. Again, not a big deal, but I think it looks a little dumb when they aren’t needed.


What about a Captcha?

As I’m sure you know, validation helps but far from eliminates form spam. If you will be creating a form that you feel will be in danger of getting spammed, you may want to consider adding a captcha. A captcha is one of those things like “Type the letters you see:” and you get a little graphic with some letters that are obscured by a bunch of lines and whatnot. Sometimes you see captchas that are as simple as “What is 1+1?”, because even a very very simple captcha is proven to be very effective at stopping random form spam.

I think the nicest freely available captcha is reCAPTCHA, which works well, is fairly easy to implement, and helps digitize books.

In an old post, I showed how to use reCAPTCHA in a contact form, and it still works. So if you are interested in adding reCAPTCHA to this contact form, check out this example.