Forms and Tables Styling
Introduction
Forms and tables are where users input data and read structured information. Poor styling here directly harms task completion, especially on mobile and for keyboard users. This chapter covers practical CSS patterns for clear form controls, validation feedback, and readable, responsive tables.
Prerequisites
- Basic input/form HTML structure (
label,input,select,textarea) - Basic pseudo-classes (
:focus-visible,:invalid,:disabled) - Basic spacing and typography styling
Form Styling Goals
Well-styled forms should be:
- readable
- easy to scan
- easy to tap/click
- clear in validation state
- keyboard accessible
Avoid styling that makes controls look decorative but less usable.
Base Form Layout
A clean vertical form stack:
.form {
display: grid;
gap: 1rem;
max-width: 560px;
}
.field {
display: grid;
gap: 0.4rem;
}Code explanation:
.formcontrols spacing between field groups.fieldkeeps label/input/help text visually grouped- grid with
gapis cleaner than many custom margins
Label Styling
label {
font-weight: 600;
color: #0f172a;
}Labels should remain clearly visible and close to controls. Do not rely on placeholder text as the only label.
Text Input Baseline
Code explanation:
width: 100%allows responsive filling of containermin-height: 44pximproves touch ergonomicsfont: inheritkeeps typography consistent with page text
Focus State for Inputs
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
outline: 3px solid #93c5fd;
outline-offset: 1px;
border-color: #2563eb;
}Focus visibility is critical for keyboard users and should never be removed without replacement.
Placeholder and Help Text
input::placeholder,
textarea::placeholder {
color: #94a3b8;
}
.help-text {
color: #475569;
font-size: 0.9rem;
}Use placeholders as hints only, not as required instructions.
Validation States
input:invalid,
select:invalid,
textarea:invalid {
border-color: #dc2626;
}
.field-error {
color: #b91c1c;
font-size: 0.875rem;
}Code explanation:
- invalid controls get stronger border cue
- error text gives explicit message beyond color alone
Pair visual cues with textual feedback for accessibility.
Disabled State
input:disabled,
select:disabled,
textarea:disabled,
button:disabled {
opacity: 0.6;
cursor: not-allowed;
}Disabled controls should look visibly inactive while still readable.
Checkbox and Radio Group Layout
.choice-group {
display: grid;
gap: 0.5rem;
}
.choice {
display: flex;
align-items: center;
gap: 0.5rem;
}This improves readability and touchability for multiple-choice fields.
Two-Column Form on Wider Screens
@media (min-width: 800px) {
.form-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
}
.form-grid .full {
grid-column: 1 / -1;
}
}Use this for compact desktop forms while keeping single-column flow on mobile.
Table Styling Goals
Readable tables need:
- clear column structure
- visible row separation
- consistent alignment
- responsive fallback strategy
Table Base Style
Code explanation:
border-collapse: collapseavoids doubled border spacing- consistent cell padding improves scanability
- header background helps users track columns
Zebra Striping and Hover Rows
tbody tr:nth-child(even) {
background: #f8fafc;
}
tbody tr:hover {
background: #eef2ff;
}Helpful for dense data tables, but keep hover subtle and maintain contrast.
Numeric Alignment
For numeric columns, align right:
.num {
text-align: right;
font-variant-numeric: tabular-nums;
}This improves comparison of values in financial or metrics tables.
Responsive Table Pattern: Horizontal Scroll
.table-wrap {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}<div class="table-wrap">
<table>...</table>
</div>Code explanation:
- wrapper adds horizontal scrolling when table exceeds viewport width
- avoids crushing columns into unreadable narrow cells
For complex datasets, this is often better than forcing stacked table cards.
Sticky Header for Long Tables
thead th {
position: sticky;
top: 0;
background: #f8fafc;
z-index: 1;
}Useful in long scrolling data tables. Ensure parent scroll context supports sticky behavior.
Accessibility Notes
- keep visible labels for form controls
- preserve focus styles
- use text + color for error states
- use
<th scope="col">for table headers - avoid tables for non-tabular page layout
Warning
Do Not Hide Critical Form Context
Removing labels or focus indicators may make forms unusable for keyboard and assistive-tech users.
Common Mistakes
| Mistake | Why it hurts | Better approach |
|---|---|---|
| Placeholder-only labeling | Poor accessibility and clarity | Use explicit <label> |
| Tiny input controls | Hard touch interaction | Keep minimum touch-friendly control size |
| Error state by color only | Ambiguous feedback | Add explicit error text |
| Tables squeezed on mobile | Unreadable columns | Use horizontal overflow wrapper |
| Center-aligned all table data | Hard numeric comparison | Left-align text, right-align numbers |
Debugging Checklist
When form/table UI looks broken:
- verify control states in DevTools (
:focus-visible,:invalid,:disabled) - check width constraints and overflow
- test keyboard-only navigation
- verify contrast in normal and error states
- test table readability at narrow viewport widths
Mini Exercise
- Build a registration form with name, email, password, and country select
- Add focus and invalid styles for controls
- Add helper text and error text styles
- Build a 6-column table with mixed text and numeric data
- Wrap table in a horizontal scroll container for mobile
- Test both keyboard navigation and mobile responsiveness
FAQ
Should I remove native form control styles completely?
Not necessarily. Start with light normalization and preserve usability cues unless you fully replace them with accessible alternatives.
Is table horizontal scrolling acceptable on mobile?
Yes, often it is the most practical and readable fallback for wide datasets.
How should I style invalid fields?
Use a clear border/state indicator plus explicit text message so users understand what to fix.
Should all table cells be center-aligned?
Usually no. Left alignment is best for text; right alignment is best for numeric columns.
Can I use CSS alone for full form validation UX?
CSS pseudo-classes help with visual states, but complex validation messaging usually needs HTML constraints and JavaScript logic.