Form Layout with Flexbox
Styling individual inputs and buttons is only half the job. The other half is layout: how labels relate to their inputs, how groups of fields are spaced from each other, and where the submit button sits. Flexbox handles all of it cleanly.
The form-group pattern
Section titled “The form-group pattern”The STO contact form wraps each label and its input in a .form-group div:
<div class="form-group"> <label for="name">Name</label> <input type="text" id="name" name="name" placeholder="Your name" required></div>This pattern is standard practice. The wrapper div gives you a target to control the relationship between the label and the input without touching the global layout.
Stacking label above input
Section titled “Stacking label above input”The label needs to sit above the input, with a small gap between them. display: flex; flex-direction: column achieves this precisely:
.form-group { display: flex; flex-direction: column; gap: 0.5rem;}flex-direction: column stacks children vertically — label first, then input. gap: 0.5rem adds consistent space between them without a margin on either child.
Why Flexbox instead of just display: block? Because gap gives you precise control over the label-to-input spacing that is independent of the elements themselves. If you need to add an error message or helper text between the label and input later, gap handles that automatically without adjusting margin values.
Label styles
Section titled “Label styles”While you are in this area, add styles for the label itself:
.form-group label { font-weight: 600; font-size: 0.9rem; color: #1a1a1a;}A slightly smaller, bolder label distinguishes it visually from the input text without requiring a different color.
Spacing form groups from each other
Section titled “Spacing form groups from each other”Each .form-group needs space below it to separate it from the next field. There are two ways to handle this:
Option A — margin on each group:
.form-group { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1.5rem;}Option B — gap on the form container:
.contact-form { display: flex; flex-direction: column; gap: 1.5rem;}Option B is cleaner. Making .contact-form a flex column container and using gap means you never need to remove the margin-bottom from the last group (the .form-group:last-child workaround). The gap only adds space between groups, not after the final one.
.contact-form { display: flex; flex-direction: column; gap: 1.5rem; max-width: 640px;}max-width: 640px constrains the form width on wide screens — a full-width contact form on a 1400px monitor is uncomfortable to fill out.
Two-column form rows
Section titled “Two-column form rows”Some forms need two fields side by side — “First Name” and “Last Name” on the same row, for example. Wrap those groups in a row container:
<div class="form-row"> <div class="form-group"> <label for="first-name">First Name</label> <input type="text" id="first-name" name="first-name"> </div> <div class="form-group"> <label for="last-name">Last Name</label> <input type="text" id="last-name" name="last-name"> </div></div>.form-row { display: flex; gap: 1.5rem;}
.form-row .form-group { flex: 1;}flex: 1 on each .form-group inside .form-row distributes the available width equally. On mobile, you may want to stack them — that is covered in Module 07 (Responsive Design).
The STO contact form does not use two-column rows, but this pattern is worth knowing for your next project.
Aligning the submit button
Section titled “Aligning the submit button”The .form-submit div wraps the submit button in the STO contact form. Align it to the right side of the form to match the conventional position for primary actions:
.form-submit { display: flex; justify-content: flex-end;}justify-content: flex-end pushes the button to the right edge of the form. If you want the button full-width on mobile, you can override this in a media query — covered in Module 07.
The complete form layout
Section titled “The complete form layout”.contact-form { display: flex; flex-direction: column; gap: 1.5rem; max-width: 640px;}
.form-group { display: flex; flex-direction: column; gap: 0.5rem;}
.form-group label { font-weight: 600; font-size: 0.9rem; color: #1a1a1a;}
.form-submit { display: flex; justify-content: flex-end;}Exercise
Section titled “Exercise”Apply the form layout to the STO contact form:
-
Add the layout CSS above to
style.css. -
Open
contact.html. Each label should sit directly above its input with a small gap. All form groups should be evenly spaced from each other. -
Verify the “Send Message” button is aligned to the right edge of the form.
-
In DevTools, toggle
flex-direction: columntoflex-direction: rowon.form-group. The label and input should move side by side — useful for visualizing how the flex axis controls the layout. -
Reduce the browser window width. On very narrow screens the form should still stack vertically, but the max-width constrains it on wide screens. Notice how
max-width: 640pxprevents the form from becoming too wide to fill out comfortably. -
If you want to test the two-column row pattern, add a
.form-rowdiv wrapping two.form-groupdivs incontact.htmltemporarily, apply the.form-rowCSS, and observe how the fields split the available width equally.
- The
.form-groupwrapper contains each<label>+<input>pair and is the target for Flexbox layout control. display: flex; flex-direction: column; gap: 0.5remon.form-groupstacks the label above the input with precise spacing.- Make the form container a flex column with
gap: 1.5remto space groups evenly — this avoids the last-child margin workaround. max-width: 640pxon the form container prevents it from stretching uncomfortably wide on large screens.- Two-column form rows use
display: flex; gap: 1.5remon a.form-rowwrapper, withflex: 1on each.form-groupinside. justify-content: flex-endon.form-submitright-aligns the submit button, matching conventional form layout patterns.
Lesson 05 adds state styling — different appearances for focused, hovered, disabled, and invalid fields.