Create a Stylish Dark Contact Form with HTML, CSS, and JavaScript

Professional web design advice.

Great new article just distributed from Envato Tuts+ Tutorials. Definitely one of the most helpful providers of free content available.

In this tutorial, we’ll walk through the process of styling basic contact form elements. We’ll examine different ways for making a form beautiful and fully functional at the same time.

Here’s the form that we’re going to build:

Note: this contact form is perfect for any dark mode UI! Learn more about how you can switch between dark and light mode using nothing but CSS:

1. Begin With the Page Markup

We’ll start from scratch with a form element which contains a heading and an unordered list. We’ll use a .container for setting a maximum width to the form and horizontally center its contents:

Inside the list we’ll place the form elements. 

The first list item, for example,  will contain a select element with four options. By default the first option is selected, yet disabled:

In the second list item we’ll place two required input fields:

The third list item includes a required and an optional input field:

The fourth list item holds a textarea:

The fifth list item contains a checkbox along with its label:

Finally, the sixth list item contains a div element and two buttons (types submit and reset):

2. Define Some Basic Styles

Before having a closer look at the individual form elements, let’s first define some CSS styles. These include a few custom variables to give us our color scheme, and some reset rules:

Note: for simplicity I won’t walk through all the CSS rules in the tutorial. You can check the rest of them by clicking the CSS tab of the demo project.

3. Build the Form Layout

On small screens all our form elements will be stacked:

The form layout on small screens

However on viewports 600 pixels wide and above, the form layout will change. More specifically:

  • We’ll arrange the elements of the second and third list items into two equal width columns.
  • The elements of the sixth list item will be arranged into three columns.
The form layout on screens 600 pixels wide and above

Thanks to CSS Grid, we can easily build the desired multi-column layout. We begin by declaring our .my-form .grid container as being a grid, then we define the columns on the grid items we need to change:

All of these rules are placed within a media query so they only take effect on viewports more than 600px wide.

4. Style the Form Elements

With our structure sorted out, we next add some initial aesthetic styles to all form elements:

Note: alternatively, for setting the textarea’s width and height, we could have used its cols and rows attributes respectively.

Add “On Focus” Styles

Each time a form element is in focus, I’d like its background color to change. Furthermore, some elements scale up a little bit, just for emphasis:

Here’s how that’s done:

Add Custom Icons

All required elements contain an icon (asterisk) positioned in the center right corner:

All required elements contain an asterisk

Similarly, the select also contains a custom icon (arrow) positioned in the center right corner:

The select contains a custom arrow

We achieve that by applying an SVG icon as the background image:

Style the Buttons

As already discussed, in our form we have two types of buttons: a submit button and a reset button. If you revisit the form markup, you’ll notice that each of those buttons contains two elements: the .back element and the .front element.

By default only their .front child appears:

By default the front button child appears

But as we hover over a button, or when it’s in focus, magic things happen. Specifically, its background color changes, the .front child disappears, and at the same time the .back child appears with a slide-in animation:

Here are the styles responsible for that behavior:

5. Create a Custom Checkbox

If you look again at the markup inside the fifth list item, you’ll see that the checkbox’s id value matches the label’s for value. That creates an association between the two elements which gives us the ability to build a custom checkbox.

As a first step we visually hide the default checkbox:

Then we take advantage of the label’s ::before and ::after pseudo-elements to generate our own checkbox. 

So, first we use the ::before pseudo-element to configure its unchecked state:

The uncheched state of our custom checkbox

And then the ::after pseudo-element along with the :checked pseudo-class to implement its checked state:

The checked state of our custom checkbox

As we did with the other form elements, we add some extra styling when the checkbox is in focus. Lastly, it’s wise to make sure users can access our form through keyboard navigation.

Check the associated styles below:

It’s worth mentioning that we could have also used some custom icons to build the desired checkbox.

6. Toggle the Buttons’ State

Initially the form buttons are disabled. That means we cannot click on them or select them:

Initially the form buttons are disabled

In our CSS we add a few styles specifically targeting these disabled elements, making it clear to the user that they cannot be interacted with:

The buttons become active as soon as the checkbox is checked:

The buttons become active as soon as the checkbox is checked

The JavaScript code that handles this functionality is shown below:


That’s it folks! Here’s what we’ve built!

In this tutorial, we covered plenty of different tips and tricks for styling contact form elements. Although we concentrated on a dark mode aesthetic, you can apply any kind of UI design using these same principles.

Hopefully you enjoyed the contact form we built here and you’ll use it as inspiration for developing your own forms. As always, thanks for reading!

Learn More About Designing Web Forms

First seen on this site: Envato Tuts+ Tutorials

Trust you enjoyed that information that they shared. You’ll find quite similar blogposts on our main website:

Leave us your reaction just below, share a quick comment and let me know which topics you would like us to cover in future articles.