In this tutorial, we’ll learn how to take advantage of flexbox to create a responsive form. What’s interesting (and exciting at the same time) is that flexbox allows us to build our form without using any media queries.
Before we start, let’s look at what we’ll be working towards (checkout the larger version to see how the form layout changes):
Form Structure
Right then, first things first, let’s dig into the form’s structure. We’ll mark it up as follows:
- We’ll use the
.flex-outer
unordered list to group the various form elements - and the
.flex-inner
unordered list to group the checkboxes. - Almost all form controls come with their associated label.
That’s it! By defining just two unordered lists (we could have used ordered lists as well), we’ve built a very clean form. Here’s what it looks like:
<form><ul class="flex-outer"><li><label for="first-name">First Name</label><input type="text" id="first-name" placeholder="Enter your first name here"></li><li><label for="last-name">Last Name</label><input type="text" id="last-name" placeholder="Enter your last name here"></li><li><label for="email">Email</label><input type="email" id="email" placeholder="Enter your email here"></li><li><label for="phone">Phone</label><input type="tel" id="phone" placeholder="Enter your phone here"></li><li><label for="message">Message</label><textarea rows="6" id="message" placeholder="Enter your message here"></textarea></li><li><p>Age</p><ul class="flex-inner"><!-- list items here --></ul></li><li><button type="submit">Submit</button></li></ul></form>
Note: we use the p
element instead of the label
element before the .flex-inner
list. This is because, in this particular case, it doesn’t make any sense to use the label
tag. This tag should be used only to associate a text label with a form control.
Here’s the markup for the checkboxes:
<ul class="flex-inner"><li><input type="checkbox" id="twenty-to-twentynine"><label for="twenty-to-twentynine">20-29</label></li><li><input type="checkbox" id="thirty-to-thirtynine"><label for="thirty-to-thirtynine">30-39</label></li><!-- more list items here --></ul>
With the markup ready, the unstyled form looks like this:
This won’t be the fanciest form you have ever seen, but it works! It’s semantic, accessible, and fluid; aspects which are arguably more important than anything.
At this point, we’re ready to start applying some styles to it.
Form Styles
Let’s begin by adding normalize and autoprefixer to our pen settings:

Next we’ll identify the flex containers. In our case, the following elements:
- Each of the list items of the
.flex-outer
list. - The
.flex-inner
list which contains all the checkboxes.
Additionally, we want to vertically center the flex items across the cross-axis.
To achieve this behavior, we set up some initial CSS rules:
.flex-outer li, .flex-inner { display: flex; flex-wrap: wrap; align-items: center; }
The next step is to specify the widths for the flex items. We begin with the flex items of the .flex-outer
list.
The main requirements:
- The width of the labels should be at least 120px and at most 220px.
- The width of the form elements that come after the labels should be at least 220px.
What does this give us? Each label along with its associated form element will be displayed on a single horizontal row when the width of the form totals at least 340px. In any other case, all form elements (apart from the checkboxes as we’ll see in a moment) will stack vertically.
Note: the aforementioned values are arbitrary–you can modify them according to your needs.
.flex-outer > li > label, .flex-outer li p { flex: 1 0 120px; max-width: 220px; } .flex-outer > li > label + *, .flex-inner { flex: 1 0 220px; }
Submit Button
Lastly, for the submit button, which is also a flex item, we define a few basic styles:
.flex-outer li button { margin-left: auto; padding: 8px 16px; border: none; background: #333; color: #f2f2f2; text-transform: uppercase; letter-spacing: .09em; border-radius: 2px; }
Checkboxes
Let’s now style the checkboxes. Remember that their flex wrapper has a minimum width of 220px.

First, we set the width of the flex items which are immediate parents of the checkboxes to 100px:
.flex-inner li { width: 100px; }
Then, we take advantage of the justify-content
property to align them across the main-axis. Note that this property has different values, but for this example, we’re only interested in the space-between
value:
.flex-inner { justify-content: space-between; }
This value works well and allows us to achieve a consistent alignment for the checkboxes and their respective labels. One thing we should mention is that this property value may distribute the elements of the final row awkwardly. At certain viewport widths you’ll see something like this:

Notice the alignment of the last two flex items. If, for some reason, you don’t like that layout and you prefer them to appear next to each other, you can try something like this:
- Remove the
justify-content
property from the flex wrapper. - Use percentages to add a fixed width to the flex items (e.g.
width: 50%
). - Use media queries to override this width. For instance, when the viewport width is greater than 992px, give flex items
width: 25%
instead ofwidth: 50%
.
Most of all, it’s important to understand two things:
- Flexbox gives us great flexibility for quickly building beautiful forms
- and all the aforementioned values work well for this specific example. For your own designs, you’ll probably need different values. For example, here the labels of the checkboxes are pretty small and for this reason we give their parent a fixed width (i.e. 100px). However, if they have different widths, it might be smarter to give them
flex: 1 100px
.
Final Styles
Before we leave, let’s add some more aesthetics to make things more presentable. Pick apart the CSS tab in the demo below to see where colors and spacing have been added:
Conclusion
As you can see, with minimal markup and the power of flexbox, we managed to build a responsive form. Hopefully now, you’ve gained some useful knowledge that will help you build your own flexbox forms.
Next Steps
If you want to take this form a step further, I have two challenges for you:
- Improve its appearance by overriding the default styles (e.g. add custom checkboxes)
- and make it dynamic. For instance, if you’re familiar with WordPress, see if it’s possible to create a Contact Form 7 or a Ninja Form which preserves the structure and styles of this form.