Form controls were added to HTML back in 1995 and CSS wasn’t released until 1996 with very little support from browsers. Most operating systems controlled the display of these features at the time. A lot has changed since then and with websites growing with their business and the rise of web applications, designers — and by extension their clients — demand control over the appearance of these elements. It’s an important aspect in web design to keep the user experience on brand.

Even with HTML5 and CSS3, there are still hurdles to developing a well-styled form for your website or web application, but the basics have expanded. I’ve outlined the pros and cons of developing a frontend form design. We’ll delve into the HTML form structure, then go through the various form elements and how to style them.

The pros & cons

Currently not all form elements have easy ways to be manipulated through CSS. More elements have been opened to developers to apply custom styles now that more digital users are familiar with how these elements should work. There is also a larger demand in corporations embracing and growing their brands to encompass all elements. CSS — and through extension SASS or LESS — allows more ways to target objects and override features such as Chrome applying a border on a focused element.

When looking at the easy elements to style, no effort is needed for the <form> and <fieldset> tags or most <input> tags except for <input type='search'>. All buttons and labels are also easily styled with CSS.

As for checkboxes and radio buttons, we’ll cover them as well as complex input fields with advanced styles in this blog. There are features of certain input fields like date-related controls with <input type='date'>, <datalist>, <progress>, <meter>, <select>, and <option> tags that cannot be manipulated at all.

HTML & form structure

It’s important to note the structure of a form in HTML5 and how to stack and nest the elements for optimized targeting through CSS. A form may use fieldsets to group elements together. Most elements should be wrapped in their corresponding label.

<form id='exampleForm' action={} onSubmit={} method='POST'>
    <fieldset>
        <label for='name'>
            <span>Name:</span>
            <input type='text' name='name' class='name' placeholder=''>
        </label>
        <label for='email'>
            <span>Email:</span>
            <input type='email' name='email' class='email' placeholder=''>
        </label>
        <label for='submit'>
            <input type='button' name='submit' class='btn btn-primary' value='SEND'>
        </label>
    </fieldset>
</form>

By wrapping the label’s text in a <span> tag, we allow extra styles to be applied and even future scripting to animate and manipulate the element. You can see how we give it a unique placement while styling the tags similar to a <div> and it’s child elements.

Box sizing & styling

The easiest styles to apply are <form>, <fieldset>, and <label>. They are virtually the same as styling <div> tags. Starting with the form itself, apply styles to contain elements and evenly align it’s child elements. Make sure to declare the form and label as relative in order to position other design elements or graphics.

Adjust the spacing for each input at once then you may target each one individually for additional styles as needed. You can group <select> and <textarea> tags in the main styles so they all match, but some may need to be applied separately. Targeting individual types of input tags requires adding the type within brackets. All types are available to target in CSS like input[type=text] and input[type=email].

form, fieldset, label {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}

input, select, textarea {
    width: 100%;
    font-size: 1rem;
    margin: 5px auto 5px;
    padding: 15px 5px 3px;
    border: 1px solid #e7e7e7;
    border-radius: 5px;
}

input[type=text] {
    // unique styles go here
}

In this example, the <span> will be positioned in the upper corner of the label by setting the position to absolute. Thereafter, set the span’s top and left styles. Giving the background a color will knockout the input’s border and become part of the border. Use margins to set space between elements and padding to give space around the input area of elements.

label span {
    font-size: 45%;
    position: absolute;
    margin-top: 5px;
    top: 12px;
    left: 5px;
}

On some input elements, placeholders may be used to add content that will be replaced once a value is added into the field. An example would be setting the name placeholder to John Doe. It will not count as the value and is cleared once the element gains the user’s focus.

<label for='example'>
    <span>Example:</span>
    <input type='text' name='example' class='example' placeholder='Type something here...'>
</label>

Select & textarea

Select and textareas require a bit more work. Selects require options and you have the ability to add a disabled option. Options require a value and the select may be given a defaultValue or you can add selected to a given option in the list. There is no way to control the style of the arrow or options display.

<select>
    <option value='*' disabled selected>-- Select one --</option>
    <option value='option1'>Option 1</option>
    <option value='option2'>Option 2</option>
</select>

Textareas will have a bit more style to adjust the height to fit your overall form’s design. There is no way to control the style of the textarea’s draggable corner.

textarea {
    height: 200px;
    min-height: 55px;
    resize: both; // to resize the textarea in both directions
    overflow: auto; // for resizing this should be set to auto, hidden, or scroll
}

Checkboxes & radio buttons

The complexities of styling checkboxes and radio buttons grows with each design from a corporate brand or identity firm. I’ll cover this in depth in another blog, but for now we can see how the basic HTML structure and styles work. Adding checked to the input tag will make it checked as the default when the form loads. We structure a <p> tag within the label and style it to fill space on either side of the input tag.

input[type=checkbox], input[type=radio] {
    width: 24px;
}

label p {
    width: 100%;
    margin: 10px auto 5px;
    padding: 0 0 0 5px;
}

The generic structure for checkboxes and radios follows the same structure as other input tags. The same span tag example has been used to show how universal this form structure can be.

<label for='checkbox'>
    <span>Checkbox example:</span>
    <input type='checkbox' name='checkbox'><p>Check this option.</p>
</label>

<label for='radios'>
    <span>Radio example:</span>
    <input type='radio' name='radios' value='one' checked><p>One</p>
    <input type='radio' name='radios' value='two'><p>Two</p>
</label>


Buttons

Adding classes from buttons already created on a site are the simplest way to applying a brand to the form. A few key styles do need to be adjusted as <input> buttons can come in either type='submit' or type='button' and could carry other styles inherited from the browser or other site styles. Otherwise, you can add all the styles you need to your own custom class and apply it to the tag and target individual states like :hover for when the user hovers over the button.

input[type=button], input[type=submit] {
    border: 1px solid #343a40;
    cursor: pointer;
}

input[type=button]:hover, input[type=submit]:hover {
    background: #343a40;
    border: 1px solid #343a40;
    color: #ffffff;
}

Multiple states exist for links and buttons. The states for basic styling include active, hover, and focus. The :checked state works for checkboxes and radios. Select tags have :selected for the specific option selected. All input fields have :disabled states that can be targeted.

input[type=button]:disabled, input[type=submit]:disabled {
    border: 1px solid #adb5bd;
    cursor: no-drop;
}

input[type=button]:disabled:hover, input[type=submit]:disabled:hover {
    border: 1px solid #343a40;
    color: #343a40;
    opacity: 0.5;
}

Apply the values necessary to each individual button within the HTML tag itself and the buttons will be displayed inline.

<input type='button' name='submit' value='CONFIRM'>
<input type='button' name='cancel' value='CANCEL'>
<input type='button' name='other' value='DISABLED' disabled>

Overriding browser styles

One of the biggest annoyances has been the introduction to certain styles a browser will force onto a website. Mostly Chrome will place dark borders around a form’s input fields. Hiding these features is very easy thanks to CSS3. Simply call on an element’s :focus styles and force the border to be your style as well as forcing the outline style to none !important. Note that any styles a browser will change can be overwritten here.

input:focus, select:focus, textarea:focus {
    border: 1px solid #e7e7e7 !important;
    outline: none !important;
}

The final form

As forms gained complexity and expanded features to tags allowing for types like <input type=date> and <input type=password>, the integration is easier than ever for frontend developers to provide programmers with an outlet for data. Certain features like the date selector are not easy to override. They require more scripting, but the basics provided are more than a frontend developer could ask for when designing a basic form. Working in more advanced styling languages like SASS and LESS offer an quick way to build the form styles. CSS3 selectors such as :hover and :focus may be nested within the style block.

A good user interface begs for a form to be legible and easy to navigate. Utilizing these newer HTML5 tags and CSS3 selectors allows a frontend developer to design and develop successful forms for any website or web application.