Forms
Forms Are Where UIs Break
Forms are the highest-risk UI area in production: they must be readable, accessible, consistent, and handle real-world states (focus, disabled, error, success). Tailwind makes forms clean when you follow a small set of patterns and do not improvise per page.
Input baseline (recommended default)
A good baseline uses a neutral border, comfortable padding, and a visible focus ring. This avoids layout shift and improves accessibility.
<label class="block">
<span class="text-sm font-medium text-slate-900">Email</span>
<input
type="email"
class="mt-2 w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm
placeholder:text-slate-400
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="you@example.com"
/>
</label>
Labels, help text, and spacing
Production forms need consistent vertical rhythm. Use space-y utilities to avoid random margins across fields.
<form class="space-y-6">
<div>
<label class="block text-sm font-medium text-slate-900">Name</label>
<input class="mt-2 w-full rounded-md border border-slate-300 px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
<p class="mt-2 text-sm text-slate-600">This will appear on your profile.</p>
</div>
<div>
<label class="block text-sm font-medium text-slate-900">Company</label>
<input class="mt-2 w-full rounded-md border border-slate-300 px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
</div>
</form>
Textarea pattern
Textareas should match inputs in border, radius, and focus behavior. Set a minimum height and allow resizing only if you want it.
<label class="block">
<span class="text-sm font-medium text-slate-900">Message</span>
<textarea
class="mt-2 w-full min-h-[120px] rounded-md border border-slate-300 px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
></textarea>
</label>
Select pattern
Select elements are tricky across browsers. Keep them simple and consistent. Consider a forms plugin if you want perfect cross-browser styling.
<label class="block">
<span class="text-sm font-medium text-slate-900">Plan</span>
<select
class="mt-2 w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option>Free</option>
<option>Pro</option>
</select>
</label>
Checkbox and radio
Use a clear click target and align label text properly. Keep spacing consistent so forms look professional.
<label class="flex items-start gap-3">
<input type="checkbox" class="mt-1 h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500" />
<span class="text-sm text-slate-700">
I agree to the terms and conditions
</span>
</label>
Error state (validation)
Error states should be obvious and consistent: change border, show helper text, and optionally add an icon. Do not rely only on color; include text feedback.
<div>
<label class="block text-sm font-medium text-slate-900">Email</label>
<input
class="mt-2 w-full rounded-md border border-red-500 px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-red-500"
value="wrong@"
/>
<p class="mt-2 text-sm text-red-600">Please enter a valid email address.</p>
</div>
Success state (optional)
Success states should be subtle. Overusing success styling makes forms noisy. Use it when confirmation is important.
<div>
<label class="block text-sm font-medium text-slate-900">Username</label>
<input
class="mt-2 w-full rounded-md border border-green-500 px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500"
value="ozan"
/>
<p class="mt-2 text-sm text-green-600">Looks good.</p>
</div>
Disabled and read-only fields
Disabled fields should look disabled and be clearly non-interactive. Read-only fields should be readable but not editable.
<input
class="w-full rounded-md border border-slate-300 px-3 py-2 text-sm
bg-slate-100 text-slate-600 cursor-not-allowed"
disabled
value="Disabled"
/>
Dark mode forms
In dark mode, inputs need different surface and border colors. Keep placeholders and helper text readable.
<input
class="w-full rounded-md border border-slate-300 bg-white px-3 py-2 text-sm
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
dark:bg-slate-900 dark:border-slate-700 dark:text-slate-100 dark:placeholder:text-slate-500"
/>
Common mistakes
- Removing focus outlines without adding focus rings.
- Inconsistent spacing between fields (random mt values).
- Error states without clear text explanation.
- Placeholder used as a label (bad for accessibility).
- Forms that break on long translations or validation messages.
Production checklist
- Use a consistent input baseline (border + ring focus).
- Use space-y-* for predictable vertical rhythm.
- Always show clear error messages, not only red borders.
- Support disabled and read-only states.
- Verify dark mode readability for borders, placeholders, and helper text.