How to Make a Slick Ajax Contact Form with jQuery and PHP

This tutorial shows you how to build a nice-looking, smooth contact form that visitors can use without having to leave the page they're reading.

How to Make a Slick Ajax Contact Form with jQuery and PHP

Contact forms can be useful way for visitors to contact the owner of a site. They're easy to use, and since they don't expose the site owner's email address in the page, they cut down on spam too.

However, contact forms can also be cumbersome, especially as they're usually on a separate page. The visitor has to visit the contact form page, fill in the details, view yet another response page, and then try to make their way back to the page they were originally reading.

Fortunately, Ajax gives us a way round this problem. By embedding the form in the page, and submitting the form data via Ajax, the user never has to leave the current page. It also provides a smoother experience for the user.

In this tutorial we'll build a nice-looking, embedded Ajax contact form that the user can summon up by clicking a link in the page. Along the way, we'll explore various topics, including:

  • HTML5 form fields
  • How to use fallback techniques to make the form function even if the browser has JavaScript turned off
  • Using CSS techniques to create attractive forms
  • Writing a secure form mailer using PHP
  • Animating page elements with jQuery, and, of course...
  • Using jQuery to make Ajax requests

Before you begin, check out the finished product by clicking the View Demo button above. This opens a new page with some dummy content, and a couple of "Send us an email" links. Click one of these links to display the form.

The demo doesn't actually send an email anywhere, but the finished code in the download is fully functional. To get the code, click the Download Code button above.

Ready? Let's get started!

Step 1: Create the markup

Let's start with the HTML for our page. This includes the form itself — we'll hide it initially using JavaScript when the page loads — and also some dummy content and a couple of "Send us an email" links that will display the form when clicked:

<!doctype html>
<html lang="en">
<head>

<title>A Slick Ajax Contact Form with jQuery and PHP</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">

</head>
<body>

<div id="content">

  <p style="padding-bottom: 50px; font-weight: bold; text-align: center;"><a href="#contactForm">~ Send us an email ~</a></p>

  <!-- Content here -->

  <p style="padding-top: 50px; font-weight: bold; text-align: center;"><a href="#contactForm">~ Send us an email ~</a></p>
 
</div>

<form id="contactForm" action="processForm.php" method="post">

  <h2>Send us an email...</h2>

  <ul>

    <li>
      <label for="senderName">Your Name</label>
      <input type="text" name="senderName" id="senderName" placeholder="Please type your name" required="required" maxlength="40" />
    </li>

    <li>
      <label for="senderEmail">Your Email Address</label>
      <input type="email" name="senderEmail" id="senderEmail" placeholder="Please type your email address" required="required" maxlength="50" />
    </li>

    <li>
      <label for="message" style="padding-top: .5em;">Your Message</label>
      <textarea name="message" id="message" placeholder="Please type your message" required="required" cols="80" rows="10" maxlength="10000"></textarea>
    </li>

  </ul>

  <div id="formButtons">
    <input type="submit" id="sendMessage" name="sendMessage" value="Send Email" />
    <input type="button" id="cancel" name="cancel" value="Cancel" />
  </div>

</form>

<div id="sendingMessage" class="statusMessage"><p>Sending your message. Please wait...</p></div>
<div id="successMessage" class="statusMessage"><p>Thanks for sending your message! We'll get back to you shortly.</p></div>
<div id="failureMessage" class="statusMessage"><p>There was a problem sending your message. Please try again.</p></div>
<div id="incompleteMessage" class="statusMessage"><p>Please complete all the fields in the form before sending.</p></div>

</body>
</html>

I've omitted the dummy content in the above code, since it's not relevant to the tutorial.

The form sends its data to a processForm.php script that does the actual emailing. (We'll write this PHP script in a moment.) By setting the form's action attribute to "processForm.php", we ensure that the form is usable even with JavaScript disabled. Later, our JavaScript will read this action attribute so that it knows where to send the Ajax request.

The form itself uses some HTML5 form features such as placeholders, the email field type, and the required attribute to ensure that all the fields have been filled in. We'll also add JavaScript validation for browsers that don't yet support HTML5 validation.

Step 2: Add the CSS

Screenshot of styled form

Now we'll add the CSS to our HTML page in order to style the page and form. The bulk of the CSS positions the form and status messages in the centre of the window, and styles the form and form fields.

<style type="text/css">


/* Add some margin to the page and set a default font and colour */

body {
  margin: 30px;
  font-family: "Georgia", serif;
  line-height: 1.8em;
  color: #333;
}


/* Set the content dimensions */

#content {
  width: 800px;
  padding: 50px;
  margin: 0 auto;
  display: block;
  font-size: 1.2em;
}

#content h2 {
  line-height: 1.5em;
}


/* Add curved borders to various elements */

#contactForm, .statusMessage, input[type="submit"], input[type="button"] {
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;  
  border-radius: 10px;
}


/* Style for the contact form and status messages */

#contactForm, .statusMessage {
  color: #666;
  background-color: #ebedf2;
  background: -webkit-gradient( linear, left bottom, left top, color-stop(0,#dfe1e5), color-stop(1, #ebedf2) );
  background: -moz-linear-gradient( center bottom, #dfe1e5 0%, #ebedf2 100% );  
  border: 1px solid #aaa;
  -moz-box-shadow: 0 0 1em rgba(0, 0, 0, .5);
  -webkit-box-shadow: 0 0 1em rgba(0, 0, 0, .5);
  box-shadow: 0 0 1em rgba(0, 0, 0, .5);
  opacity: .95;
}


/* The form dimensions */

#contactForm {
  width: 40em;
  height: 33em;
  padding: 0 1.5em 1.5em 1.5em;
  margin: 0 auto;
}


/* Position the form in the middle of the window (if JavaScript is enabled) */

#contactForm.positioned {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin-top: auto;
  margin-bottom: auto;
}


/* Dimensions and position of the status messages */

.statusMessage {
  display: none;
  margin: auto;
  width: 30em;
  height: 2em;
  padding: 1.5em;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.statusMessage p {
  text-align: center;
  margin: 0;
  padding: 0;
}


/* The header at the top of the form */

#contactForm h2 {
  font-size: 2em;
  font-style: italic;
  letter-spacing: .05em;
  margin: 0 0 1em -.75em;
  padding: 1em;
  width: 19.5em;  
  color: #aeb6aa;
  background: #dfe0e5 url('images/stamp.jpg') no-repeat 15em -3em; /* http://morguefile.com/archive/display/606433 */
  border-bottom: 1px solid #aaa;
  -moz-border-radius: 10px 10px 0 0;
  -webkit-border-radius: 10px 10px 0 0;  
  border-radius: 10px 10px 0 0;
}


/* Give form elements consistent margin, padding and line height */

#contactForm ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

#contactForm ul li {
  margin: .9em 0 0 0;
  padding: 0;
}

#contactForm input, #contactForm label {
  line-height: 1em;
}


/* The field labels */

label {
  display: block;
  float: left;
  clear: left;
  text-align: right;
  width: 28%;
  padding: .4em 0 0 0;
  margin: .15em .5em 0 0;
  font-weight: bold;
}


/* The fields */

input, textarea {
  display: block;
  margin: 0;
  padding: .4em;
  width: 67%;
  font-family: "Georgia", serif;
  font-size: 1em;
  border: 1px solid #aaa;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;    
  border-radius: 5px;
  -moz-box-shadow: rgba(0,0,0,.2) 0 1px 4px inset;
  -webkit-box-shadow: rgba(0,0,0,.2) 0 1px 4px inset;
  box-shadow: rgba(0,0,0,.2) 0 1px 4px inset;
  background: #fff;
}

textarea {
  height: 13em;
  line-height: 1.5em;
  resize: none;
}


/* Place a border around focused fields, and hide the inner shadow */

#contactForm *:focus {
  border: 1px solid #66f;
  outline: none;
  box-shadow: none;
  -moz-box-shadow: none;
  -webkit-box-shadow: none;
}


/* Display correctly filled-in fields with a green background */

input:valid, textarea:valid {
  background: #dfd;
}


/* The Send and Cancel buttons */

input[type="submit"], input[type="button"] {
  float: right;
  margin: 2em 1em 0 1em;
  width: 10em;
  padding: .5em;
  border: 1px solid #666;
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;  
  border-radius: 10px;
  -moz-box-shadow: 0 0 .5em rgba(0, 0, 0, .8);
  -webkit-box-shadow: 0 0 .5em rgba(0, 0, 0, .8);
  box-shadow: 0 0 .5em rgba(0, 0, 0, .8);
  color: #fff;
  background: #0a0;
  font-size: 1em;
  line-height: 1em;
  font-weight: bold;
  opacity: .7;
  -webkit-appearance: none;
  -moz-transition: opacity .5s;
  -webkit-transition: opacity .5s;
  -o-transition: opacity .5s;
  transition: opacity .5s;
}

input[type="submit"]:hover,
input[type="submit"]:active,
input[type="button"]:hover,
input[type="button"]:active {
  cursor: pointer;
  opacity: 1;
}

input[type="submit"]:active, input[type="button"]:active {
  color: #333;
  background: #eee;
  -moz-box-shadow: 0 0 .5em rgba(0, 0, 0, .8) inset;
  -webkit-box-shadow: 0 0 .5em rgba(0, 0, 0, .8) inset;
  box-shadow: 0 0 .5em rgba(0, 0, 0, .8) inset;
}

input[type="button"] {
  background: #f33;
}


/* Header/footer boxes */

.wideBox {
  clear: both;
  text-align: center;
  margin: 70px;
  padding: 10px;
  background: #ebedf2;
  border: 1px solid #333;
}

.wideBox h1 {
  font-weight: bold;
  margin: 20px;
  color: #666;
  font-size: 1.5em;
}

</style>

<!-- Some IE7 hacks and workarounds -->

<!--[if lt IE 8]>
<style>

/* IE7 needs the fields to be floated as well as the labels */

input, textarea {
  float: right;
}

#formButtons {
  clear: both;
}

/*
  IE7 needs an ickier approach to vertical/horizontal centring with fixed positioning.
  The negative margins are half the element's width/height.
*/

#contactForm.positioned, .statusMessage {
  left: 50%;
  top: 50%;
}

#contactForm.positioned {
  margin-left: -20em;
  margin-top: -16.5em;
}

.statusMessage {
  margin-left: -15em;
  margin-top: -1em;
}

</style>
<![endif]-->

Let's look at some interesting sections of the CSS:

  1. Style for the contact form and status messages
    We give the form and status boxes a nice gentle top-to-bottom gradient using -webkit-gradient and -moz-linear-gradient, and we also add a drop shadow with box-shadow (and its vendor-specific variants). Finally, we give the form and message boxes an opacity of .95 (95%), which makes the page content just show through — a nice subtle effect.
  2. Position the form in the middle of the window (if JavaScript is enabled)
    Initially, we simply place the form inline after the page content. This is so that the form can be used for non-JavaScript-enabled browsers without getting in the way of the content. However, for JavaScript browsers, we want the form to appear in the centre of the window, over the top of the content.

    Our #contactForm.positioned rule does just that. It uses fixed positioning, sets the top, bottom, left and right values all to zero, and ensures that all 4 margins are set to auto. This centres the element both horizontally and vertically in most modern browsers. Later we'll use our JavaScript to add the positioned class to the form.

    We also position the status message boxes in the same way.

  3. The header at the top of the form
    Our form includes a nice "Send us an email..." header with an image of a postage stamp. Our #contactForm h2 rule styles this header. We give the text a large italic style and space the letters out slightly. We also add margin and padding to create space around and inside the header. We use some negative left margin (-.75em) on the header to bypass the padding on the form, so that the header goes right to the left edge of the form. We also set the width of the header to 19.5em so that it exactly matches the width of the form.

    Why -.75em and 19.5em? Because ems cascade, and we've set our font size to 2em. So -.75em actually becomes -1.5em (the width of the form's padding), and 19.5em becomes 39em (the width of the form, minus 1em for the h2's padding). Phew! Maybe I'll use pixels next time... :)

    We also set the heading's colour, give it a dark background, position the postage stamp image in the top right corner, add a thin bottom border, and add curved top corners.
  4. The fields
    We give the input and textarea fields an attractive font, a rounded border using border-radius, and a gentle inner shadow using box-shadow. We also float the field labels left so that they sit alongside the fields. When a field is focused (clicked on or moved to with the Tab key), we give it a blue border and remove the shadow. We also set outline: none to remove the blue outline added by some browsers. Finally, we use the :valid pseudo-class to give correctly completed fields a green background, for those browsers that support HTML5 form validation.
  5. The Send and Cancel buttons
    input[type="submit"] selects the Send Email button, while input[type="button"] selects the Cancel button. We float them right to position them side by side, and add some margin to give them space. We give them a fixed width, and some padding to make them a decent size. We add a rounded border and subtle drop shadow, and specify text and background colours. We also make the buttons slightly transparent (opacity: .7), and make them fully transparent when hovered over to highlight them. We use a CSS transition to fade the opacity slowly. Finally, when the buttons are clicked (:active) we move the shadow inside the buttons to give a "pressed" appearance, and give them a black-on-white colour scheme.

Step 3: Build the PHP form mailer

We've now created our form page, and styled the form. The next step is to build a short PHP script to actually send the email messages. This script will reside on the web server. When the user submits the form, the form's data is sent to the PHP script, which then sends the email and returns a response indicating whether or not the email was sent successfully.

Here's the PHP script — call it processForm.php, and save it in the same folder as the form page you created in Steps 1 and 2:

<?php

// Define some constants
define( "RECIPIENT_NAME", "John Smith" );
define( "RECIPIENT_EMAIL", "john@example.com" );
define( "EMAIL_SUBJECT", "Visitor Message" );

// Read the form values
$success = false;
$senderName = isset( $_POST['senderName'] ) ? preg_replace( "/[^\.\-\' a-zA-Z0-9]/", "", $_POST['senderName'] ) : "";
$senderEmail = isset( $_POST['senderEmail'] ) ? preg_replace( "/[^\.\-\_\@a-zA-Z0-9]/", "", $_POST['senderEmail'] ) : "";
$message = isset( $_POST['message'] ) ? preg_replace( "/(From:|To:|BCC:|CC:|Subject:|Content-Type:)/", "", $_POST['message'] ) : "";

// If all values exist, send the email
if ( $senderName && $senderEmail && $message ) {
  $recipient = RECIPIENT_NAME . " <" . RECIPIENT_EMAIL . ">";
  $headers = "From: " . $senderName . " <" . $senderEmail . ">";
  $success = mail( $recipient, EMAIL_SUBJECT, $message, $headers );
}

// Return an appropriate response to the browser
if ( isset($_GET["ajax"]) ) {
  echo $success ? "success" : "error";
} else {
?>
<html>
  <head>
    <title>Thanks!</title>
  </head>
  <body>
  <?php if ( $success ) echo "<p>Thanks for sending your message! We'll get back to you shortly.</p>" ?>
  <?php if ( !$success ) echo "<p>There was a problem sending your message. Please try again.</p>" ?>
  <p>Click your browser's Back button to return to the page.</p>
  </body>
</html>
<?php
}
?>

This script is fairly straightforward. Let's break it down:

  1. Define some constants
    First we define some config options for the name and email address of the person who will receive the email message. (Change these to your own name and email address.) We also set a subject for the message.
  2. Read the form values
    Next we check for our 3 form fields, senderName, senderEmail and message, in the posted form data. For each field, we check if it exists. If it does then we pass its value through a regular expression to remove any potentially malicious characters that a spammer might try to use, and store the result in a variable. If it doesn't exist then we set the variable to an empty value.
  3. If all values exist, send the email
    If the 3 field values all contain data then we send the email. First we construct the recipient string from the recipient name and email address. Then we add a "From:" header to the message using the name and email address that the visitor entered in the form. This is the "From:" value that the recipient will see in their email program. Finally, we use the PHP mail() function to send the email message, storing the return value in the variable $success. (mail() returns true if it managed to send the email, or false otherwise.)
  4. Return an appropriate response to the browser
    Once we've attempted to send the email, we send a "success" or "error" message back to the browser as appropriate. If the request URL contained an "ajax" parameter then we know the form was submitted via Ajax using our JavaScript code, so we simply return the value "success" or "error" to the JavaScript, which will then display an appropriate message to the user. However, if the form was submitted without using Ajax then the user must have JavaScript turned off in their browser. In this situation, we display a more helpful error message in the browser, with instructions to the user to use their Back button to return to the page.

    Our JavaScript will add the ajax parameter to the URL when it submits the form, as you'll see in Step 6.

    1. Step 4: Include the jQuery library and set the delay

      Our form is actually functional now. You can open the page in a browser, click the "Send us an email" link to jump to the form, fill in the fields, and submit the form to send the message.

      However, we're now going to enhance our form using JavaScript to make the experience nicer for the user.

      We'll use jQuery to do most of the heavy lifting, so the first step is to include the jQuery library in the page's head element:

      <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
      

      Here we've linked directly to the jQuery library on Google's CDN, but you can download the library and host it on your own server if you prefer.

      We'll also add a global config variable, messageDelay, to control how long the message boxes appear on the screen. This value is in milliseconds. Feel free to change it to a shorter or longer time:

      <script type="text/javascript">
      
      var messageDelay = 2000;  // How long to display status messages (in milliseconds)
      

      Step 5: Write the init() function

      The first stage of our form-enhancing JavaScript is the init() function. This sets up the form so that it can be shown and hidden on demand, and also modifies the form so that it will be submitted using our JavaScript, rather than sent natively by the browser.

      Here's the code:

      // Init the form once the document is ready
      $( init );
      
      
      // Initialize the form
      
      function init() {
      
        // Hide the form initially.
        // Make submitForm() the form’s submit handler.
        // Position the form so it sits in the centre of the browser window.
        $('#contactForm').hide().submit( submitForm ).addClass( 'positioned' );
      
        // When the "Send us an email" link is clicked:
        // 1. Fade the content out
        // 2. Display the form
        // 3. Move focus to the first field
        // 4. Prevent the link being followed
      
        $('a[href="#contactForm"]').click( function() {
          $('#content').fadeTo( 'slow', .2 );
          $('#contactForm').fadeIn( 'slow', function() {
            $('#senderName').focus();
          } )
      
          return false;
        } );
        
        // When the "Cancel" button is clicked, close the form
        $('#cancel').click( function() { 
          $('#contactForm').fadeOut();
          $('#content').fadeTo( 'slow', 1 );
        } );  
      
        // When the "Escape" key is pressed, close the form
        $('#contactForm').keydown( function( event ) {
          if ( event.which == 27 ) {
            $('#contactForm').fadeOut();
            $('#content').fadeTo( 'slow', 1 );
          }
        } );
      
      }
      

      Let's look at each chunk of the above code:

      1. Init the form once the document is ready
        We use the jQuery object, $, to trigger our init() function once the DOM is ready.
      2. Hide the form, set the submit handler, and position the form
        The first thing we do inside the init() function itself is make some changes to our form, #contactForm.

        First we hide it from the page using the jQuery hide() method. Then we set its submit event handler to our submitForm() function (which we'll write in a moment). This ensures that, when the user submits the form, submitForm() is called instead of the native browser form submission kicking in. Finally, we add the positioned CSS class to the form to reposition it in the centre of the browser window.
      3. Make the "Send us an email" links open the form
        Next we bind an anonymous event handler function to the "Send us an email" links' click events. This function fades out the page content so it's only just visible in the background; fades the contact form in; and sets the focus on the "Your Name" field, ready for the user to start filling in the form. Finally, the function returns false to prevent the links from being followed.
      4. When the "Cancel" button is clicked, close the form
        Now we bind another anonymous function to the "Cancel" button's click event, so that the user can close the form by clicking the button. The function simply fades the form out, and fades the page content back in.
      5. When the "Escape" key is pressed, close the form
        Similarly we bind a function to the contact form's keydown event, so that we can read any key the user presses when they're viewing the form. In this function, we check if the user has pressed the "Escape" key (character code: 27). If they have then we close the form by fading it out, and fading the content in.

      Step 6: Write the submitForm() function

      Screenshot of form buttons

      We've now set up our form so that, rather than being submitted in the usual fashion, it will trigger the submitForm() function when the user submits it. This function needs to do some validation and, if all is well, submit the form data to the PHP script via Ajax.

      Here's the function in full:

      // Submit the form via Ajax
      
      function submitForm() {
        var contactForm = $(this);
      
        // Are all the fields filled in?
      
        if ( !$('#senderName').val() || !$('#senderEmail').val() || !$('#message').val() ) {
      
          // No; display a warning message and return to the form
          $('#incompleteMessage').fadeIn().delay(messageDelay).fadeOut();
          contactForm.fadeOut().delay(messageDelay).fadeIn();
      
        } else {
      
          // Yes; submit the form to the PHP script via Ajax
      
          $('#sendingMessage').fadeIn();
          contactForm.fadeOut();
      
          $.ajax( {
            url: contactForm.attr( 'action' ) + "?ajax=true",
            type: contactForm.attr( 'method' ),
            data: contactForm.serialize(),
            success: submitFinished
          } );
        }
      
        // Prevent the default form submission occurring
        return false;
      }
      

      Here's how the function works:

      1. Store the contact form in a variable
        Since we'll be using it a lot throughout the function, we start off by storing the contact form element in a contactForm variable. This element is available to our function as the this variable, since the function is the event handler for the element's submit event. We wrap the element in a jQuery object to make it easier to work with.
      2. Check all the fields are filled in
        Now we check that each field's value is not empty by using the jQuery val() method on each field.
      3. Display a warning if the form isn't completed
        If 1 or more of the fields are empty, we fade out the form, then fade in the #incompleteMessage div, which contains the "Please complete all the fields..." message. We keep the message there for the time specified by the messageDelay variable, then fade it out again. Once it's faded out, we fade the form back in so that the user can complete it.
      4. Submit the form if it is completed
        Now we get to the meat of the JavaScript. If the form is completed then we first fade out the form, and fade in the "Sending your message..." box. Now we call the jQuery ajax() method to submit the form via Ajax to the PHP script. We pass the following arguments to the method:
        url
        The URL to send the form to. We grab this from the form's action attribute, and append an ajax=true parameter to the query string so that our PHP script knows the form was sent via Ajax, rather than via the usual method.
        type
        The type of request to make ("POST" or "GET"). We grab this from the form's method attribute, which in this case is set to "POST".
        data
        The data to send with the request. For this, we call the jQuery serialize() method on the contact form object. This method takes all the field names and values in the form and encodes the data in a query string. We then pass this string to the ajax() method so it can send the data to the PHP script.
        success
        This is a callback function that will be called once the Ajax request has finished and the browser has received the response from the server. We set this to our submitFinished() function, which we'll write in a moment.
      5. Prevent the default form submission occurring
        Finally, our event handler returns false to prevent the form being submitted in the usual way.

      Step 7: Write the submitFinished() function

      Screenshot of success message

      The last function we need to write is submitFinished(), which is called once the Ajax response from the PHP script has been received by the browser. This function needs to check the response and display a success or error message as appropriate:

      // Handle the Ajax response
      
      function submitFinished( response ) {
        response = $.trim( response );
        $('#sendingMessage').fadeOut();
      
        if ( response == "success" ) {
      
          // Form submitted successfully:
          // 1. Display the success message
          // 2. Clear the form fields
          // 3. Fade the content back in
      
          $('#successMessage').fadeIn().delay(messageDelay).fadeOut();
          $('#senderName').val( "" );
          $('#senderEmail').val( "" );
          $('#message').val( "" );
      
          $('#content').delay(messageDelay+500).fadeTo( 'slow', 1 );
      
        } else {
      
          // Form submission failed: Display the failure message,
          // then redisplay the form
          $('#failureMessage').fadeIn().delay(messageDelay).fadeOut();
          $('#contactForm').delay(messageDelay+500).fadeIn();
        }
      }
      
      </script>
      

      The function works as follows:

      1. Get the response
        jQuery passes the response from the PHP script as an argument to the submitFinished() function. We take this string and pass it through the jQuery trim() method to remove any whitespace.
      2. Fade out the "sending" message
        Next we fade out the "Sending your message..." box by calling the jQuery fadeOut() method.
      3. If email was sent successfully, display a success message
        If the response variable holds the string "success", as returned by our PHP script, then we know that the email was successfully queued for delivery. So we fade in the success message, hold it for a couple of seconds, then fade it out. We also reset the form fields to empty values, in case the user wants to send another message. Finally, once the success message has faded out, we fade the page content back in.
      4. If there was a problem, display a failure message
        If the PHP script returned anything other than "success" then we know there was a problem with the submission, so we display the failure message stored in the #failureMessage div, then fade the form back in so that the user can correct any problems with the form.

      And that's the end of our JavaScript!

      Summary

      We've now built our slick Ajax contact form. Not only does it look good, but it's easy to use, and the visitor can send an email without ever having to leave the page they are reading. Nice!

      Here's the demo again:

      I hope you enjoyed following this tutorial. Feel free to use the code in your own projects if you like. As always, if you have any comments, suggestions or questions on the tutorial, please do post them in the responses below.

      Have fun!

      Learn PHP With Ease!

      Written by Matt Doyle — ELATED's resident Web programming expert — Beginning PHP 5.3 is a complete introduction to PHP, covering everything in these tutorials and lots more besides. Find out how to:

      • Set up PHP on your computer
      • Use strings, arrays, functions and objects
      • Create interactive Web forms
      • Handle cookies and sessions
      • Work with files on the server
      • Build database-driven sites with MySQL
      • Send emails from your scripts
      • Create images on the fly with PHP
      • Work with regular expressions
      • Write robust, secure PHP applications

      ...and lots more!

      “What a pleasure it's been spending hours and hours studying PHP with this magical book.” — Lulio, Florida
      “The book is not only great for learning, but I find myself using it constantly as a reference as well!” — David A. Stoltz

      Buy Beginning PHP 5.3 now from Amazon.comBeginning PHP 5.3 or Amazon.co.ukBeginning PHP 5.3.

      Follow Elated

      Related articles

      Responses to this article

      20 most recent responses (oldest first):

      19-May-14 23:30
      I am sending mail through godaddy and down to my gmail account. It works great when someone puts their hotmail account in and now their gmail account, It's just not coming though when they use their yahoo email account. I am not sure about outlook or any other email accounts at this time. I think the problem has to be with this SMTP stuff you are talking about so I will go school myself on that and see if I can find a fix. I think this is the best looking contact form out there so I will get it to work. When I find the fix I will let you know. In the mean time if something comes to mind. Please let me know. Thank you for your time.
      20-May-14 22:27
      Chris....I finely understand what you mean about route mail via an external SMTP server. I was actually trying to route the emails straight to my gmail account from the processform.php file. Everything was showing up but the yahoo emails for some reason where not. Then I created a new email name in my godaddy account and put that email name in the processform.php file. I put a forward to my gmail from my new godaddy email and everything works. I am going to assume thats what you mean by route mail via an external SMTP server, (ie... use the email name on the server not you gmail name) Thank you for the help......
      21-May-14 10:35
      Good, and thanks for returning and posting the steps you took to solve it, that will possibly assist future viewers of this thread.

      And to vegas as it transpires your guess was correct but you STILL need to learn how to address people without using profanities and infantile insults.
      22-May-14 10:54
      I followed along with this tutorial and I must say, wow. Very insightful. Thank you so much.

      I am running into one problem while trying to add a little extra functionality and I cannot seem to wrap my mind around it. If I leave everything as is, the code works great and it sends the email just fine. But what I am trying to add into the PHP page is the functionality to where, before the email is sent, it stores the variables into a MYSQL database. However, the moment I add the code below, I receive the message: "There was a problem sending your message. Please try again." If I remove the INSERT statement from the PHP page, everything goes back to running smoothly and sending the email. Here is the current code I am using to try and insert the data into the database:



      <?php

      // Define some constants
      define( "RECIPIENT_NAME", "John Smith" );
      define( "RECIPIENT_EMAIL", "someemail@email.com" );
      define( "EMAIL_SUBJECT", "Visitor Message" );

      // Read the form values
      $success = false;
      $senderName = isset( $_POST['senderName'] ) ? preg_replace( "/[^\.\-\' a-zA-Z0-9]/", "", $_POST['senderName'] ) : "";
      $senderAddress = isset( $_POST['senderAddress'] ) ? preg_replace( "/[^\.\-\' a-zA-Z0-9]/", "", $_POST['senderAddress'] ) : "";
      $senderCity = isset( $_POST['senderCity'] ) ? preg_replace( "/[^\.\-\' a-zA-Z0-9]/", "", $_POST['senderCity'] ) : "";
      $senderState = isset( $_POST['senderState'] ) ? preg_replace( "/[^\.\-\' a-zA-Z0-9]/", "", $_POST['senderState'] ) : "";
      $senderZip = isset( $_POST['senderZip'] ) ? preg_replace( "/[^\.\-\' a-zA-Z0-9]/", "", $_POST['senderZip'] ) : "";
      $senderPhone = isset( $_POST['senderPhone'] ) ? preg_replace( "/[^\.\-\' a-zA-Z0-9]/", "", $_POST['senderPhone'] ) : "";
      $senderEmail = isset( $_POST['senderEmail'] ) ? preg_replace( "/[^\.\-\_\@a-zA-Z0-9]/", "", $_POST['senderEmail'] ) : "";
      $message = isset( $_POST['message'] ) ? preg_replace( "/(From:|To:|BCC:|CC:|Subject:|Content-Type:)/", "", $_POST['message'] ) : "";

      //set default active status
      $active = '1';

      //insert into database before sending response to the browser
      $sql = "INSERT INTO `Quotes` (`quote_name`) VALUES ('$senderName')";
      $sql_result = mysql_query($sql,$connection) or die ('Could not Insert the Quote Request');

      // If all values exist, send the email
      if ( $senderName && $senderEmail && $message ) {
      $recipient = RECIPIENT_NAME . " <" . RECIPIENT_EMAIL . ">";
      $headers = "From: " . $senderName . " <" . $senderEmail . ">";
      $success = mail( $recipient, EMAIL_SUBJECT, $message, $headers );
      }

      // Return an appropriate response to the browser
      if ( isset($_GET["ajax"]) ) {
      echo $success ? "success" : "error";
      } else {
      ?>
      <html>
      <head>
      <title>Thanks!</title>
      </head>
      <body>
      <?php if ( $success ) echo "<p>Thanks for sending your message! We'll get back to you shortly.</p>" ?>
      <?php if ( !$success ) echo "<p>There was a problem sending your message. Please try again.</p>" ?>
      <p>Click your browser's Back button to return to the page.</p>
      </body>
      </html>
      <?php
      }
      ?>


      If anyone can help me with this issue, that would be incredible. Thank you so much.
      22-May-14 13:03
      I wanted to post again because, after much head-banging against a wall (LOL), I finally realized the errors of my way. The problem was that I was trying to insert into a database that I hadn't connected to yet. So al I had to do was actually connect to the database (what a novel idea) and all was well.

      Thanks again Matt for a wonderful tutorial.
      22-May-14 14:56
      After getting everything to work properly, I actually do have 1 question about the difference between the example on this site and the one I implemented on my site.

      When I downloaded the source codes and applied the files to my server, and tried it out, it worked great both on my desktop and on my mobile phone. On my mobile phone, the modal window fits nicely into the size of my screen. However, when I view my version that I altered a bit on my mobile phone, the modal does not shrink down, and most of the important buttons and text fields fall off the screen and makes it impossible to use. Does anybody have an idea of what would make mine differently? Here is my CSS code that I used:



      /* Set default display to NONE */

      #contactForm {
      display: none;
      overflow-y: scroll;
      }

      /* Add curved borders to various elements */

      #contactForm, .statusMessage, input[type="submit"], input[type="button"] {
      -moz-border-radius: 10px;
      -webkit-border-radius: 10px;
      -o-border-radius: 10px;
      border-radius: 10px;
      }

      #contactForm, .statusMessage {
      color: #666;
      background-color: #fff;
      background: -webkit-gradient( linear, left bottom, left top, color-stop(0,#dfe1e5), color-stop(1, #ebedf2) );
      background: -moz-linear-gradient( center bottom, #dfe1e5 0%, #ebedf2 100% );
      border: 1px solid #aaa;
      -moz-box-shadow: 0 0 16px rgba(0, 0, 0, .5);
      -webkit-box-shadow: 0 0 16px rgba(0, 0, 0, .5);
      box-shadow: 0 0 16px rgba(0, 0, 0, .5);
      z-index: 999;
      }

      /* The form dimensions */

      #contactForm {
      width: 640px;
      height: 528px;
      padding: 0 24px 24px 24px;
      margin: 0 auto;
      }

      /* Position the form in the middle of the window (if JavaScript is enabled) */

      #contactForm.positioned {
      position: fixed;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      margin-top: auto;
      margin-bottom: auto;
      }

      /* Dimensions and position of the status messages */

      .statusMessage {
      display: none;
      margin: auto;
      width: 480px;
      height: 32px;
      padding: 24px;
      position: fixed;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      }

      .statusMessage p {
      text-align: center;
      margin: 0;
      padding: 0;
      }

      /* The header at the top of the form */

      #contactForm h2 {
      font-family: nevis;
      font-size: 28px;
      margin: 0 5%;
      padding: 16px;
      width: 90%;
      color: #fff;
      background-color: #810d0d;
      border-bottom: 1px solid #aaa;
      }

      /* Give form elements consistent margin, padding and line height */

      #contactForm ul {
      list-style: none;
      margin: 0;
      padding: 0;
      }

      #contactForm ul li {
      margin: 14px 0 0 0;
      padding: 0;
      }

      #contactForm input, #contactForm label {
      line-height: 16px;
      }

      /* The field labels */

      label {
      display: block;
      float: left;
      clear: left;
      text-align: right;
      width: 28%;
      padding: 6px 0 0 0;
      margin: 2px 8px 0 0;
      font-family: nevis;
      font-weight: bold;
      }

      /* The fields */

      input, textarea {
      display: block;
      margin: 0;
      padding: 6px;
      width: 67%;
      font-family: "Georgia", serif;
      font-size: 16px;
      border: 1px solid #aaa;
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      border-radius: 5px;
      -moz-box-shadow: rgba(0,0,0,.2) 0 1px 4px inset;
      -webkit-box-shadow: rgba(0,0,0,.2) 0 1px 4px inset;
      box-shadow: rgba(0,0,0,.2) 0 1px 4px inset;
      background: #fff;
      }

      textarea {
      height: 208px;
      line-height: 24px;
      resize: none;
      }

      /* Place a border around focused fields, and hide the inner shadow */

      #contactForm *:focus {
      border: 1px solid #66f;
      outline: none;
      box-shadow: none;
      -moz-box-shadow: none;
      -webkit-box-shadow: none;
      }

      /* Display correctly filled-in fields with a green background */

      input:valid, textarea:valid {
      background: #dfd;
      }

      /* The Send and Cancel buttons */

      input[type="submit"], input[type="button"] {
      float: right;
      margin: 32px 16px 0 16px;
      width: 160px;
      padding: 8px;
      border: 1px solid #666;
      -moz-border-radius: 10px;
      -webkit-border-radius: 10px;
      border-radius: 10px;
      -moz-box-shadow: 0 0 8px rgba(0, 0, 0, .8);
      -webkit-box-shadow: 0 0 .8px rgba(0, 0, 0, .8);
      box-shadow: 0 0 8px rgba(0, 0, 0, .8);
      color: #fff;
      background: #0a0;
      font-size: 16px;
      line-height: 16px;
      font-weight: bold;
      opacity: .7;
      -webkit-appearance: none;
      -moz-transition: opacity .5s;
      -webkit-transition: opacity .5s;
      -o-transition: opacity .5s;
      transition: opacity .5s;
      }

      input[type="submit"]:hover,
      input[type="submit"]:active,
      input[type="button"]:hover,
      input[type="button"]:active {
      cursor: pointer;
      opacity: 1;
      }

      input[type="submit"]:active, input[type="button"]:active {
      color: #333;
      background: #eee;
      -moz-box-shadow: 0 0 8px rgba(0, 0, 0, .8) inset;
      -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, .8) inset;
      box-shadow: 0 0 8px rgba(0, 0, 0, .8) inset;
      }

      input[type="button"] {
      background: #f33;
      }

      .modal-red-star {
      font-family: nevis;
      font-size: 24px;
      font-weight: bold;
      color: #810d0d;
      padding-top: 6px;
      }


      Any help on this issue would be greatly appreciated.
      23-Jun-14 10:24
      I'm implementing this form into my site as we speak because without doubt, it is unbelievably slick! BUT one problem I've been trying to sort out, can anyone figure out why theres a big blank space in the message text area and it'll only display the placeholder image after deleting some whitespace? thanks

      my site is at http://joewinfield.net/portfolio
      24-Jun-14 04:27
      A textarea element will display everything that is between the start and end tags, so if your source code has a line break in the tag structure, ... So will the rendered document.
      25-Jun-14 06:07
      Chrishirst you're right! i accidentally left in whitespace when cleaning up how my code was laid out. the smallest things always catch you, thanks
      27-Jun-14 12:18
      I know you're showing how to make a contact form appear so it's non-obstrusive on a page, but if I just wanted to load the contact form so it appears within a page(without onclick) and still functional, how can it be done?
      28-Jun-14 12:17
      Make it visible by default rather than requiring the mouse click.
      09-Jul-14 03:45
      Hi Matt, still using this great script but I've recently been hit (big time) by spambots.

      Rather than mess around with captchas I added a line of code to capture the spammer/bot's IP address and include this in the email I receive from the form, then I add that IP address to a blacklist I use to filter out unwelcome guests and redirect them to somewhere else.

      In case this helps anyone else I thought I'd share:

      1) Add the following line to processForm.php, at the end of the section near the top which says "// Read the form values"

      $message .= "\n" . $_SERVER["REMOTE_ADDR"];

      2) Add the following script to the top of the page containing your contact form:

      // blacklist spammers

      $deny = array("123.242.153.113", "123.242.153.*", "95.67.80.*", "27.153.163.223", "27.153.163.*"); // remember no comma after last one
      if (in_array ($_SERVER['REMOTE_ADDR'], $deny)) {
      header("location: http://www.example.com/");
      exit();
      }

      There are a couple of examples there to show how I do it - I add the offending IP address AND I also use a wildcard "*" to block any similar IP addresses.

      You can redirect the spammer to another address - on a company site I take care of I actually redirect them to our company Facebook page instead.
      13-Jul-14 03:31
      I entered all the code but when i tried it, it just gave me the "Please complete all the fields in the form before sending." message and all the fields were filled in. desperate for help
      13-Jul-14 18:31
      Without seeing YOUR code, were not going to be able to provide any.
      19-Sep-14 08:42
      Helo house please am having "There was a problem sending your message. Please try again." error and all the fields are complete. please help its urgent
      19-Sep-14 10:01
      read the reply above yours and below the one asking EXACTLY the same question.
      19-Sep-14 11:48
      I have two questions. First is there a fix the yahoo mailing problem. I have my mail which is hosted on godaddy.com forward my mail to my gmail. If the sender post their email account with a domain of @gmail and @hotmail it gets forwarded to my mail wit no problems, but if the sender post with @yahoo domain I don't receive anything.

      Second question: i'm trying to add the css on to an external stylesheet like I do for all css, but for some reason the css only works when it is embedded in the main html page. Am I missing something?

      Please help me out
      19-Sep-14 12:12
      "Am I missing something?"

      Probably.


      "but if the sender post with @yahoo domain I don't receive anything."

      You probably need to ask Godaddy support about that.
      19-Sep-14 12:26
      Is there anyway to send the emails directly to my email rather than fowarding it i.e. to an email outside the server which it is hosted in?

      And I figured out the external stylesheet problem, had to back out of the directory with ../
      19-Sep-14 16:21
      "Is there anyway to send the emails directly to my email rather than fowarding it i.e. to an email outside the server which it is hosted in? "

      Again that has to be a no idea.

      Does your server have a MTA installed on it?

      View all 275 responses »

      Post a response

      Want to add a comment, or ask a question about this article? Post a response.

      To post responses you need to be a member. Not a member yet? Signing up is free, easy and only takes a minute. Sign up now.

      Top of Page