CSS — Forms
The baseline reset
Form controls ignore inheritance by default — force consistency:
input,
select,
textarea,
button {
font: inherit;
color: inherit;
}
The input recipe
.field {
margin-bottom: 16px;
}
.field label {
display: block;
font-weight: 600;
font-size: .875rem;
margin-bottom: 6px;
}
.field input {
width: 100%;
padding: 10px 12px;
border: 1px solid #cbd5e1;
border-radius: 8px;
transition: border-color .2s, box-shadow .2s;
}
.field input:focus {
outline: none;
border-color: #0d9488;
box-shadow: 0 0 0 3px rgba(13,148,136,.25);
}
(Comfortable rounded inputs whose teal focus ring appears only when active.)
width:100% + the container controlling size = inputs that adapt to any layout. Pair labels with for="id" so clicking focuses.
States that communicate
input:hover:not(:focus) { border-color: #94a3b8; }
input:user-invalid { /* modern: after user typed wrong */
border-color: #dc2626;
}
input:user-valid {
border-color: #16a34a;
}
input:disabled {
background: #f1f5f9;
cursor: not-allowed;
}
::placeholder { color: #94a3b8; }
Pair color signals with icons/text — color alone fails accessibility.
Selects, textareas, resize
textarea {
min-height: 120px;
resize: vertical; /* allow height drag only */
}
select {
appearance: none; /* drop native arrow */
background-image: url("chevron.svg"); /* custom arrow */
background-repeat: no-repeat;
background-position: right 12px center;
padding-right: 36px;
}
Checkboxes & radios — custom look
Style the label via the checked state:
.check {
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
}
.check input { accent-color: #0d9488; width: 18px; height: 18px; }
accent-color recolors native checkboxes/radios/progress in one line — 95% of the custom-checkbox need gone.
Fully bespoke (switch style):
.switch input { position: absolute; opacity: 0; } /* keep accessible! */
.switch span {
width: 44px; height: 24px;
background: #cbd5e1; border-radius: 999px;
position: relative; transition: background .2s;
}
.switch span::after {
content: "";
position: absolute;
top: 2px; left: 2px;
width: 20px; height: 20px;
background: white; border-radius: 50%;
transition: translate .2s;
}
.switch input:checked + span { background: #0d9488; }
.switch input:checked + span::after { translate: 20px 0; }
.switch input:focus-visible + span { outline: 2px solid #0d9488; }
The hidden-but-present input keeps keyboard + screen-reader support.
Form layout patterns
/* stacked (mobile default) — see field above */
/* two-column rows on wide screens */
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.form-grid .full { grid-column: 1 / -1; }
<form class="form-grid">
<div class="field">First name</div>
<div class="field">Last name</div>
<div class="field full">Email</div>
</form>
Checklist: label every input · visible :focus-visible · real error text (not red borders alone) · autocomplete attributes · generous touch targets.
Mini Practice
- Styled login card: email + password + button.
- Focus rings + hover borders + placeholder colors.
- accent-colored checkboxes; then one custom switch.
- Two-column grid collapsing to one under 600px.
- Native validation styled via user-invalid with helper text.
Next: counters →
Related Topics
Frequently Asked Questions about Forms
What is Forms in CSS?
Forms is a fundamental concept in CSS. This lesson explains it step by step with clear examples, making it easy for beginners to understand.
How do I learn Forms?
Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Forms.
Why is Forms important in CSS?
Forms is essential for CSS development. Understanding this concept will help you write better code and solve real-world problems more effectively.