Styling forms
After Preflight form fields look almost bare: no border and no padding. That is convenient — you decide how they look, and they look the same in every browser. Let us build a sign-up form for the shop's new arrivals.
An input
A border, padding, rounded corners and a visible focus state — the basic set for any field:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<label class="block max-w-xs">
<span class="text-sm font-medium text-gray-700">Email</span>
<input type="email" placeholder="anna@example.com"
class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 placeholder:text-gray-400 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 focus:outline-none">
</label>A label above the field and a gray hint inside it. Click into the field — the border turns blue and a soft ring appears.
Select and textarea
The same classes fit <select> and <textarea>, so all fields of a form look alike:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="max-w-xs space-y-3">
<select class="block w-full rounded-lg border border-gray-300 px-3 py-2">
<option>Audio</option>
<option>Chargers</option>
</select>
<textarea rows="3" class="block w-full rounded-lg border border-gray-300 px-3 py-2" placeholder="Comment"></textarea>
</div>Checkboxes and accent color
Checkboxes and radio buttons are drawn by the browser. The easiest way to recolor them is the accent- utility:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<label class="flex items-center gap-2">
<input type="checkbox" checked class="size-4 accent-indigo-600">
<span>Send me discounts</span>
</label>The checked box is blue, like the shop's buttons.
Errors and states
user-invalid: applies when a field is filled in wrongly and the user has already interacted with it — unlike invalid:, which paints an empty required field right away. disabled: styles a disabled field, file: the file picker button:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<form class="max-w-xs space-y-3">
<input type="email" required placeholder="Email"
class="block w-full rounded-lg border border-gray-300 px-3 py-2 user-invalid:border-red-500 user-invalid:text-red-600">
<input type="text" disabled value="Anna"
class="block w-full rounded-lg border border-gray-300 px-3 py-2 disabled:bg-gray-100 disabled:text-gray-500">
<input type="file"
class="block w-full text-sm file:mr-3 file:rounded-lg file:border-0 file:bg-indigo-50 file:px-3 file:py-2 file:text-indigo-700">
</form>Type text without an @ into the first field and click elsewhere — the border turns red. The "Choose file" button got a light blue background.
The @tailwindcss/forms plugin
The official plugin gives fields a neat base style, including custom-drawn checkboxes. In a project it is installed and added with the @plugin directive:
npm install -D @tailwindcss/forms@import "tailwindcss";
@plugin "@tailwindcss/forms";After that fields get a border and padding right away, and utilities only adjust them. The browser script cannot load plugins from npm, so the examples in this lesson do without it.
Common mistake
Not connecting the label to the field. If the <span> sits next to the <input> rather than inside a <label>, clicking the text does not focus the field, and screen readers do not know what the text belongs to. Wrap the field in a <label>, as in the examples above, or connect them with the for and id attributes.