Go to homepage

Projects /

Contact Form

A simple and easy to customize contact form.

Contact Form
Check our new component library →

We have been receiving lots of requests about adding a contact form to our library. Here it is! A minimal and customizable snippet to throw a semantic form into your web projects on the fly.

There are some optional features (i.e. floating labels) that can be easily removed in case you want the form to be simpler. We included all common form elements like radio buttons, checkboxes, select, error messages etc.

All icons are from our Nucleo project.

Let's dive into the code!

Creating the structure

Having the HTML structure of a standard form in your pocket is already a way to save time, isn't it? The <form> element contains 2 <fieldset> elements, that split the form in two main blocks. Each form element (that usually contains a <label> + <input>) is wrapped into a simple <div>. This allows us to easily control spacing by setting margins just once.

Here is the html structure. You may notice some specific classes, we'll discuss about that in the CSS section.

<form class="cd-form floating-labels">
   <fieldset>
      <legend>Account Info</legend>

      <div class="error-message">
         <p>Please enter a valid email address</p>
      </div>

      <div class="icon">
         <label class="cd-label" for="cd-name">Name</label>
         <input class="user" type="text" name="cd-name" id="cd-name" required>
      </div> 

      <!-- ... -->
   </fieldset>

   <fieldset>
      <legend>Project Info</legend>

      <div>
         <h4>Budget</h4>

         <p class="cd-select icon">
            <select class="budget">
               <option value="0">Select Budget</option>
               <option value="1">&lt; $5000</option>
               <option value="2">$5000 - $10000</option>
               <option value="3">&gt; $10000</option>
            </select>
         </p>
      </div> 

      <div>
         <h4>Project type</h4>

         <ul class="cd-form-list">
            <li>
               <input type="radio" name="radio-button" id="cd-radio-1" checked>
               <label for="cd-radio-1">Choice 1</label>
            </li>
               
            <li>
               <input type="radio" name="radio-button" id="cd-radio-2">
               <label for="cd-radio-2">Choice 2</label>
            </li>

            <li>
               <input type="radio" name="radio-button" id="cd-radio-3">
               <label for="cd-radio-3">Choice 3</label>
            </li>
         </ul>
      </div>

      <!-- ... -->

      <div class="icon">
         <label class="cd-label" for="cd-textarea">Project description</label>
         <textarea class="message" name="cd-textarea" id="cd-textarea" required></textarea>
      </div>

      <div>
         <input type="submit" value="Send Message">
      </div>
   </fieldset>
</form>

Adding style

The CSS is divided in 3 parts: 1) Form, 2) Custom icons and 3) Floating labels. This way, if you want the essential coding part, you can just grab 1) Form.

How to add a custom icon: you need to add a class to the element (input/select/textarea) that you want to stylize with the icon (i.e. class .user to the first input element). Secondly you need to add the .icon class to its parent. Finally in CSS you'll define the custom background-image. If the input field is required, you need to define 2 background-images, just like in the example below:

.cd-form .icon input, .cd-form .icon select, .cd-form .icon textarea {
  padding-left: 54px !important;
}
.cd-form .user {
  background: url("../img/cd-icon-user.svg") no-repeat 16px center;
}
.cd-form [required].user {
  background: url("../img/cd-icon-user.svg") no-repeat 16px center, url("../img/cd-required.svg") no-repeat top right;
}

Floating labels are activated through the .floating-labels class added to the .cd-form element. In case you never heard of this UX pattern, it was first introduced by Matt D. Smith. He also explained how he came up with this idea in this interesting article. In my opinion, it's a great UX solution: it allows you to use labels as placeholders at first, then turning them into animated labels once the user starts typing. This way the user has always a clue of what kind of information has been provided already.

You'll notice in CSS the .floating-labels class derives from the .js class, which is added by Modernizr when javascript is supported by the browser. This way if javascript is disabled by the browser/user, the form is still accessible with standard labels (the .floating-labels class produces no effect).

In order to stylize an obligatory field, we took advantage of the required boolean HTML5 attribute. While the error is just a class added to the form element.

.cd-form [required] {
  background: url("../img/cd-required.svg") no-repeat top right;
}

.cd-form .error {
  border-color: #e94b35 !important;
}

Another interesting point is the way we created custom radio and check buttons. You'll find the source code pretty straightforward. In a nutshell, we set position: absolute; and opacity: 0; for the radio and check input elements, and replaced them with custom ::before and ::after pseudo elements of the <label>.

Events handling

Javascript has been used to activate the floating labels. If a .floating-labels element exists in the DOM, we initialize the floatLabels() function: it grabs the form input fields (targeted as next elements of the .cd-label) and binds the checkVal() function to the keyup() event to detect if the user has started typing.

if( $('.floating-labels').length > 0 ) floatLabels();

function floatLabels() {
   var inputFields = $('.floating-labels .cd-label').next(); 
   inputFields.each(function(){
      var singleInput = $(this); 
      singleInput.keyup(function(){
         checkVal(singleInput);  
      });
   });
}

The checkVal() function checks the input value: if not empty, it adds the float class to its previous .cd-label element, otherwise it removes it.

Project duplicated

Project created

Globals imported

There was an error while trying to export your project. Please try again or contact us.