CSS Input Generator
Text, textarea, number, OTP and search — with the browser quirks handled.
We will never share it.
text 17.72:1 · placeholder 2.56:1 — placeholder is too faint to read.
.field label {
display: block;
margin-bottom: 6px;
font-size: 12px;
font-weight: 500;
color: #18181b;
}
.field input {
width: 100%;
padding: 9px 12px;
font-size: 14px;
font-family: inherit;
line-height: 1.4;
color: #18181b;
background: #ffffff;
border: 1px solid #d4d4d8;
border-radius: 8px;
transition: border-color 0.15s, box-shadow 0.15s;
}
.field input::placeholder {
color: #a1a1aa;
}
.field input:focus {
outline: none;
border-color: #2563eb;
box-shadow: 0 0 0 3px rgb(37 99 235 / 0.25);
}
.field input[aria-invalid="true"] {
border-color: #dc2626;
}
.field input:disabled {
opacity: 0.55;
cursor: not-allowed;
}
.field .helper {
margin-top: 6px;
font-size: 11px;
color: #a1a1aa;
}
.field .helper[data-error="true"] {
color: #dc2626;
}
Every field type has its own trap
Inputs look like the simplest thing to style and are not. Number fields draw spinner arrows that take three rules to remove, textareas default to monospace, Safari repaints search boxes, and OTP fields need specific attributes or the SMS autofill never appears. Each field type here brings its own fixes.
How to use it
-
Pick a field type
Text, textarea, number, OTP or search. Each one adds the browser quirks it actually needs — the number spinner reset, the Safari search reset, the OTP autocomplete attributes.
-
Shape it
Padding, font size, radius, border and focus ring width, with the preview updating to the exact values the CSS will contain.
-
Check every state
Default, focus, error and disabled. All four are written into the output whether you look at them or not.
-
Watch the contrast
Text and placeholder contrast are both checked live. Placeholder grey is the one that usually fails.
-
Copy the code
CSS with all the states, semantic HTML with the right input attributes, or the Tailwind class string.
Removing number spinners takes three rules
Two WebKit pseudo-elements handle Chrome, Safari and Edge:
::-webkit-outer-spin-button and ::-webkit-inner-spin-button, both
needing -webkit-appearance: none and margin: 0. Firefox
ignores those entirely and needs appearance: textfield on the input. Snippets
that only include the WebKit half are why the arrows keep coming back.
Textareas inherit almost nothing
Browsers default a textarea to a monospace font at a smaller size than your body text, so
font-family: inherit and an explicit font-size are not optional. Add
field-sizing: content and the textarea grows as you type, which replaces the old
scrollHeight JavaScript entirely.
Focus rings on inputs are not like buttons
A button should use :focus-visible so the ring only appears for keyboard users.
A text field should not — remove the focus state on click and the field looks inert, with no
indication of where typing will land. Use plain :focus here.
Placeholders are not labels
Placeholder text vanishes the moment someone types, taking the only description of the field
with it, and the default grey usually fails contrast. Keep a real <label>
and treat the placeholder as an example, not a name. The contrast reading above the preview
checks it as you change colours.
Laying out the form
Field styling is one half; arranging them is the other. A two-column form with full-width fields for long values is a grid problem — build it in the grid generator and paste these field styles in.
Frequently asked questions
How do I remove the spinner arrows from a number input?
::-webkit-outer-spin-button and ::-webkit-inner-spin-button with -webkit-appearance: none; margin: 0 for Chrome, Safari and Edge, plus appearance: textfield on the input itself for Firefox. Missing the Firefox line is why the arrows usually survive.How do I style a textarea in CSS?
resize to control the drag handle and min-height so it does not start as a single line. Set font-family: inherit — textareas default to monospace in most browsers, which is almost never what you want.How do I make a textarea grow with its content?
field-sizing: content with a min-height. It replaces the old JavaScript trick of syncing scrollHeight on every keystroke. Support is good in Chromium and shipping elsewhere, and it degrades to a normal fixed-height textarea.How do I build an OTP input with CSS?
maxlength="1", inputmode="numeric" and text-align: center. Put autocomplete="one-time-code" on the first one only, which is what lets iOS and Android offer the code from SMS. Each input needs its own aria-label since there is no visible label per box.Should input focus use :focus or :focus-visible?
:focus. :focus-visible is right for buttons — it hides the ring on mouse clicks — but a text input that shows no focus state when clicked looks broken and loses the one signal that tells you where typing will go.What contrast does placeholder text need?
Why does my search input look wrong in Safari?
type="search", including an inner shadow and a cancel button. Reset it with -webkit-appearance: none on the input and on ::-webkit-search-cancel-button.