Make Forms Fun with Flexbox

Share this article

An enhanced version of our form

Curious about deep-diving into Flexbox? Check out our Master CSS Layouts with Flexbox course by front-end dev and General Assembly London teacher Guy Routledge. It’s available for all SitePoint members. Watch our sample video from the course below.

Loading the player…

I’ll come clean: HTML forms are rarely fun – but they’re a necessary part of web development. Fortunately, some historical difficulties can be alleviated with CSS flexbox.

Consider how forms are typically coded without flexbox. What HTML mark-up would you use for the following fields?

Final example of our form

We would normally use mark-up as such:

<div>
  <label for="name">name</label>
  <input id="name" name="name" type="text" />
</div>

<div>
  <label for="experience">experience</label>
  <select id="experience" name="experience"><!-- options --></select>
</div>

<div>
  <input id="html" name="html" type="checkbox" />
  <label for="html">HTML</label>
</div>

<div>
  <input id="css" name="css" type="checkbox" />
  <label for="css">CSS</label>
</div>

<div>
  <input id="javascript" name="javascript" type="checkbox" />
  <label for="javascript">JavaScript</label>
</div>

A number of issues arise as you begin to apply CSS styling:

  1. The HTML source order of the label and field is inconsistent and depends on the type. The label typically comes before the field but is better after checkboxes and radio buttons. You must re-order your mark-up if you change the type.
  2. Consistently aligning and sizing inputs, textareas and select boxes can be difficult. Most have default styles which can be awkward to change in some browsers.
  3. Aligning a label next to its field requires trial and error to get the positioning correct.
  4. It’s (currently) impossible to style a label according to the field’s activation or content state when it appears first.

Flexbox can solve these issues. We can use clean and consistent HTML where the label is placed after every field and it’s not necessary to add helper CSS classes.

What’s Flexbox?

Flexbox is a magical way to layout multiple elements on the page. They can be aligned in horizontally, vertically, in order, reversed and sized in relation to other elements. Flexbox can be confusing and, even after using them for months, you’ll need to consult documentation now and again. However, the most basic CSS to enable flexbox:

.container {
  display: flex;
}

That’s it. All child elements of the .container are now flexbox items which, by default, will size themselves into a single row.

The main difference between flexbox and grid systems (such as the new CSS Grid Module) is that flexbox is one-dimensional. Flexbox items are laid in a line and wrap when necessary. Grids are two-dimensional with defined columns and non-wrapping rows.

Flexbox is less powerful than a grid but it’s ideal for laying out smaller components such as navigation menus, lists and form fields.

Flexbox tools and resources:

Why no Classes?

Those who have adopted CSS philosophies such as SMACSS or BEM will be horrified by the dearth of class definitions in this article. The HTML and tag-targetting CSS is intended to keep the code clean and aid understanding without distraction.

You could consider the code as a base style for all forms on your site – presuming you have a consistent layout throughout. You can add classes should you want to use but they may not necessary for smaller sites or demonstrations.

Flexboxing the Form

The code for the image above can be seen in action here:

See the Pen Flexboxed Forms by SitePoint (@SitePoint) on CodePen.

Examine the HTML and you’ll notice that label elements are always defined after the field regardless of the type, e.g.

<div>
  <input id="name" name="name" type="text" />
  <label for="name">name</label>
</div>

<div>
  <select id="experience" name="experience"><!-- options --></select>
  <label for="experience">experience</label>
</div>

<div>
  <input id="html" name="html" type="checkbox" />
  <label for="html">HTML</label>
</div>

Each <div> is set as a flexbox container and align-items: center ensures labels and fields align vertically:

fieldset div {
  display: flex;
  align-items: center;
}

The field and the label are now flexbox items but, in most cases, they’re in the wrong order because we want the label first:

Basic flexbox styles

(This is how the form appears on older browsers such as IE9 and below)

We can fix ordering using the appropriately-named order property which is set to a positive or negative integer. The lower the number, the “sooner” it is displayed on the page:

label {
  order: 1;
  width: 10em;
  padding-right: 0.5em;
}

input, textarea, select {
  order: 2;
  flex: 1 1 auto;
}

We apply a width and padding to the label to ensure they align consistently. One disadvantage of flexbox is that you may need to adjust this width if you introduce longer text labels.

Note the flex: 1 1 auto setting for input, textarea and select fields. flex is a shorthand property which specifies how the item can alter its dimensions to fill the available space. The three values are:

  • flex-grow – the amount of space a flex item can grow in relation to others, e.g. a value of 2 would permit the item to be twice the width of any item with a value of 1.
  • flex-shrink – similarly, the amount of space a flex item can shrink in relation to others.
  • flex-basis – the initial width of a flex item.

flex: 1 1 auto essentially says: use whatever space remains. Our field elements are sized the same and there’s no need to mess around with paddings and borders!

Initial label and field styles

Unfortunately, our checkbox fields are now styled incorrectly (yes, that wouldn’t have happened if we used class names!) but we can target checkboxes and radio fields directly to fix that. The following code places the field first again, stops it using all the space and applies a margin which matches our label width set above:

input[type="checkbox"], input[type="radio"] {
  order: 1;
  flex: none;
  width: auto;
  margin-left: 10em;
}

We can also target the associated labels using a sibling selector (~ or + is fine) because they come after the field in our HTML source. We can switch off the default width and apply a little padding:

input[type="checkbox"] ~ label, input[type="radio"] ~ label {
  width: auto;
  padding-left: 0.4em;
}

Sprinkle on a few colors and styles and we have a glorious form which will look great no matter what fields we throw at it.

Final example of our form

Label Style

Another advantage of the label coming last is that we can style it according to the state of its field. For example, set the label to red when the field has focus:

input:focus ~ label, textarea:focus ~ label, select:focus ~ label {
  color: #933;
}

or make the label bold when a checkbox or radio button is checked:

input:checked ~ label {
  font-weight: bold;
}
An enhanced version of our form

Add a few CSS transitions and you can make labels to resize, move, fade or have any other animated effect.

Flexbox Browser Support

Flexbox is supported in all current mainstream browsers. IE11 has several flexbox issues but they don’t arise in the simple properties we’re using for this example. IE10 requires -ms- prefixes but will work.

Older browsers display all fields before the label but the tab ordering remains correct and it is obvious which field you’re using.

My only hesitation is screen readers. Confusion could arise if a reader relies on the HTML source order rather than the associated label text. I’m not aware of any specific issues but please let me know if you encounter one!

Finally, if this encourages you to apply flexbox liberally over your forms, be aware that display: flex cannot be applied to <fieldset> elements owing to bugs in Chrome and Firefox. Hope that tip saves you some of the hours I wasted!

Frequently Asked Questions (FAQs) about Making Forms Fun with Flexbox

What is Flexbox and why is it important in form design?

Flexbox, short for Flexible Box Module, is a layout model in CSS that allows you to design complex layouts with ease and efficiency. It is particularly useful in form design because it provides a more efficient way to align, distribute space, and accommodate different screen sizes and display devices. Unlike other CSS layout techniques, Flexbox is direction-agnostic and can work in either a row or column fashion. This makes it a powerful tool for building responsive forms that look great on any device.

How can I create a basic form using Flexbox?

Creating a basic form using Flexbox involves defining a flex container and then specifying the layout of the flex items within it. Here’s a simple example:

.form-container {
display: flex;
flex-direction: column;
}

.form-item {
margin: 10px 0;
}
In this example, .form-container is the flex container and any child elements with the class .form-item are the flex items. The flex-direction: column; property makes the form items stack vertically.

How can I align form items using Flexbox?

Flexbox provides several properties for aligning items along the main and cross axes. These include justify-content, align-items, and align-self. For example, to center a form item horizontally and vertically within its container, you could use the following CSS:

.form-container {
display: flex;
justify-content: center;
align-items: center;
}

How can I make a form responsive using Flexbox?

Flexbox makes it easy to create responsive forms. By using the flex-wrap property, you can specify whether flex items should wrap onto multiple lines or not. For example, to make a form responsive, you could use the following CSS:

.form-container {
display: flex;
flex-wrap: wrap;
}
In this example, the form items will wrap onto multiple lines if there’s not enough space in the container.

How can I control the order of form items using Flexbox?

Flexbox provides the order property, which allows you to control the order of flex items within a container. By default, flex items are displayed in the order they appear in the source code. However, you can change this order by assigning a positive or negative integer value to the order property. For example:

.first-item {
order: 2;
}

.second-item {
order: 1;
}
In this example, the item with the class .second-item will be displayed before the item with the class .first-item, regardless of their order in the source code.

How can I control the size of form items using Flexbox?

Flexbox provides the flex property, which is a shorthand for flex-grow, flex-shrink, and flex-basis. This property allows you to control the size of flex items relative to the rest of the items in the container. For example:

.form-item {
flex: 1;
}
In this example, all form items will take up an equal amount of space within the container.

How can I create complex form layouts using Flexbox?

Flexbox allows you to create complex form layouts by nesting flex containers. This means you can have a flex container inside another flex container. For example, you could create a form with two columns of inputs like this:

.form-container {
display: flex;
}

.column {
display: flex;
flex-direction: column;
}
In this example, the .form-container is a flex container with two child elements, each of which is also a flex container (column) with its own child elements (the form inputs).

How can I use Flexbox to align form labels and inputs?

You can use Flexbox to align form labels and inputs by setting the align-items property to center. This will vertically align the labels and inputs along the cross axis. For example:

.form-item {
display: flex;
align-items: center;
}
In this example, the form labels and inputs within each .form-item will be vertically centered.

How can I use Flexbox to create a form with equally spaced inputs?

You can use the justify-content property with the value space-between to create a form with equally spaced inputs. This will distribute the available space evenly between the form items. For example:

.form-container {
display: flex;
justify-content: space-between;
}
In this example, the form items within the .form-container will be equally spaced.

How can I use Flexbox to create a form with inputs of varying widths?

You can use the flex property to create a form with inputs of varying widths. By assigning different flex values to the form items, you can control their relative sizes. For example:

.small-input {
flex: 1;
}

.large-input {
flex: 3;
}
In this example, the .large-input will take up three times as much space as the .small-input.

Craig BucklerCraig Buckler
View Author

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's created enterprise specifications, websites and online applications for companies and organisations including the UK Parliament, the European Parliament, the Department of Energy & Climate Change, Microsoft, and more. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler.

AdvancedCSScss flexboxcss3 flexboxflexboxflexbox layoutsHTML5 Formspatrickc
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week