Whether you are a veteran or just getting started with web development, working with web forms is not the sexiest thing but there is no avoiding them. Forms on a website are critical to the website's mission and the visitors using them. In this post I am going to show you how to properly style webforms and form elements so you can ensure they are consistent with your brand and provide a pleasant user experience.
I have recording video tutorials on some of the concepts covered in this post. Scroll to the bottom if you are the kind of person who learns better watching tutorials.
One thing about forms you can count on is that they are not consistent. In today's API era forms can be generated from any source and you don't always have control of their HTML. I personally work with Drupal a lot and even within it forms can originate from Views, Blocks, Nodes, Paragraphs, Modules, and more. I imagine this is the case with most Content Management Systems. So how do you address something where you can't always predict source or markup of forms?
Whether is Drupal or other system, it is best to let that system dictate the markup of forms. Try to bend a system to your needs can prove challenging and not worth the trouble. This is the approach I take and so far this has worked very well for me.
As a Front-End developer for many years, I love a good css class. They make my job a lot easier than not having a class. When it comes to form elements however, it is best to ignore classes and rely solely in attributes. What attributes you may be asking yourself? Let's take a look
The type attribute in form elements make it easy to style them in a global manner. Rather than styling form elements based on their css class or ID, the type attribute is the best approach. Each form field has a type attribute which makes it possible for browsers to render the element as expected. The type attribute can also play a factor in Javascript and form handling, but for now we are going to focus on styling.
Input fields: Input fields such as text fields, are probably the most common form elements in a form. But don't let its simplicity fool you because text fields come in many types; the most common being text
. this is the type for a typical text box where you can type just about any kind of information. This sometimes leads to developers using it for anything including for data that should be in a different form type. Let's take a look at the various types a text field can be:
email
, this provides you with a custom keyboard on mobile devices that make it easier to type a common url.As you can see from the examples above, text fields may seem simple but they come in all flavors. In most cases, the goal of form elements is to be styled the same across an entire site. So it is recommended you style these elements globally so no matter where they are used they automatically inherit the intended styles. So how do you style them globally? Let's take a look:
Here are a couple of examples of differnt input fields which we will style to ensure they all look similarly everywhere.
<input type="text" name="firstname">
<input type="password" name="password">
<input type="email" name="email">
input[type='text'],
input[type='password'],
input[type='email'],
input[type='tel'],
input[type='search'],
textarea {
background-color: #ffffff;
border: 1px solid #000000;
height: 40px;
padding: 10px;
width: 100%;
}
textarea {
height: initial;
}
By using the element's type
attribute we can collectively style them with a single set of rules. As you may have noticed I included textarea
as on of the elements because I want textareas boxes (multi-row textbox), to inherit all of the styles from text boxes with the exception of the height property; thus we override the height property while keeping all other styles the same as text boxes.
Buttons are elements you typically want to display with consistent styles across your entire website. This includes buttons you may create yourself and those provided by the content management system you may be working with. So similarly to input fields above, we can't always rely on IDs or classes to style them. However, similarly to the input fields above, we can rely on the type
attribute to style the different type of buttons in our site. Different type of buttons? yes, there are different types. Let's tae a look.
<a class='button'>I want to look like a button</a>
<button>I'm an actual button</button>
<input type='submit' value='Yo tambien'>
<input type='reset' value='Me too'>
type=['reset']
) should look slightly different because it's not a primary button, it's more of a secondary button..button,
button,
input[type='submit'],
input[type='reset'] {
background-color: rebeccapurple;
border-radius: 2px;
border: 2px solid rebeccapurple;
color: #ffffff;
cursor: pointer;
display: inline-block;
font-size: 18px;
line-height: 1;
padding: 20px 40px;
text-align: center;
text-decoration: none;
white-space: nowrap;
margin-bottom: 20px;
}
.button:hover,
.button:focus,
button:hover,
button:focus,
input[type='submit']:hover,
input[type='submit']:focus {
background-color: rgb(126, 63, 189); /* lighter purple */
color: #ffffff;
text-decoration: none;
}
input[type='reset'] {
background-color: #ffffff;
border-color: rebeccapurple;
color: rebeccapurple;
}
input[type='reset']:hover,
input[type='reset']:focus {
background-color: #ffffff;
border-color: #444444;
color: #444444;
}
Probably the hardest elements to style due to their dynamic nature, they have a hard time fitting in with the rest of HTML elements. Rather than link you to another blog post where you can copy and paste the necessary CSS to style these elements, I am walk you through the process of styling them.
Checkout the Codepen for these elements.
The typical markup for a checkbox or radio button looks like this:
<div class="checkbox__item">
<input type="checkbox" id="checkbox1" name="checkboxname" value="Item 2">
<label for="checkbox1">Item 2</label>
</div>
<div class="checkbox__item">
<input type="checkbox" id="checkbox2" name="checkboxname" value="Item 2">
<label for="checkbox2">Item 2</label>
</div>
<div class="radio__item">
<input type="radio" id="radio1" name="radioname" value="Item 2">
<label for="radio1">Item 1</label>
</div>
<div class="radio__item">
<input type="radio" id="radio2" name="radioname" value="Item 2">
<label for="radio2">Item 2</label>
</div>
Out of the box, you can not style the native checkbox nor radio button elements. To be able to apply custom styles we need to do it in a hacky way. This is my favorite way to style these elements.
/* visually hide the native checkbox and radio buttons. */
input[type='checkbox'],
input[type='radio'] {
position: absolute;
opacity: 0;
}
visibility-hidden
or display: none
are not viable options./* Add space to the left of the label for later use. */
label {
position: relative;
padding-left: 35px;
}
relative
position on the label as we prepare to add pseudo elements in the next steps./* Draw a square box with border using a pseudo element (`::before`). */
input[type='checkbox'] + label::before {
border: 2px solid #e15b00;
content: '';
display: inline-block;
height: 24px;
left: 0;
position: absolute;
top: -2px;
width: 24px;
}
+
sign. The sibling element being the label
element. If you look at the markup we wrote above, you will notice that the checkbox and the label are siblings. This is also true for the radio button and its label.::before
pseudo element on the label, we are drawing a 24px
square box.content:
, even if it's value is empty as shown above.2px
border on the box. This box is what will be presented as the actual checkbox for the user to interact with (check/uncheck).absolute
position, we are positioning just to the left of the label. The position of the box is in relation to the label's position (hence relative
position on the label)./* Draw checkmark using a ::after pseudo elment on the label */
input[type='checkbox'] + label::after {
border-bottom: 3px solid #fff;
border-left: 3px solid #fff;
content: '';
display: inline-block;
height: 10px;
left: 4px;
position: absolute;
top: 2px;
transform: rotate(-45deg);
width: 18px;
}
::after
pseudo element on the label. This means we are drawing the checkmark symbol after the label
element.3px
. By rotating the box negative 45 degrees, this makes it look like a checkmark.absolute
position on the checkmark so we can position it right in the middle of the box we drew before.Before proceeding with the styles, let's repeat the steps above but this time for the radio buttons. These styles are extremely similar with the exception of in stead of drawing a square box, we will be drawing a circle with an outline, and instead of a checkmark, we will be drawing a filled circle in the middle of the outlined circle.
/* Draw a circle and add borders to it */
input[type='radio'] + label::before {
border-radius: 50%;
border: 2px solid #e15b00;
content: '';
display: inline-block;
height: 24px;
left: 2px;
position: absolute;
top: -4px;
width: 24px;
}
/* Draw an inner circle */
input[type='radio'] + label::after {
background-color: #e15b00;
border-radius: 50%;
content: '';
display: inline-block;
height: 20px;
left: 6px;
position: absolute;
top: 0;
width: 20px;
}
radio
and we are using border-radius
to draw a perfect circle./* Hide checkmark and inner circle by default */
.radio input[type='radio'] + label::after,
.checkbox input[type='checkbox'] + label::after {
content: none;
}
content:
to none
. This will present the checkboxes and radio buttons unchecked./* Show checkmark and inner circle when input is checked */
input[type='radio']:checked + label::after,
input[type='checkbox']:checked + label::after {
content: '';
}
:checked
pseudo class (input[type='radio']:checked
, input[type='checkbox']:checked
), we then show the checkmark or inner circle by setting the content:
property's value to empty (''
i.e. removing none
). The :checked
pseudo class becomes available when the checkbox or radio buttons are click-checked and when that happens, then we show the checkmark or inner circle./* When box is checked, add background color. */
input[type='checkbox']:checked + label::before {
content: '';
background-color: #e15b00;
}
:checked
pseudo class is present./* Add focus styles when elements are in focus */
input[type='radio']:focus + label::before,
input[type='checkbox']:focus + label::before {
outline: rgb(59, 153, 252) auto 5px;
}
:focus
pseudo class, we are adding basic outline styles to show the "on focus" state of the inputs. We need to do this since we are not using the native input elements. If we were, the browser would automatically add these styles to our inputs.I have recorded tutorials on severalof these things. Check them out if you are the kind of person who learns better through video tutorials.