28 Tailwind CSS input fields for sign-up forms, checkout flows, search bars, and dashboard settings — floating and notched labels, underline and drawn-border focus effects, neon and frosted and brutalist styling, live validation, password strength and reveal, OTP and credit-card and phone entry, tag chips, file drop zones, auto-grow textareas, and native date, time, colour and range controls. Scoped under .tif-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.
Building a whole Tailwind app, not just this component?
You just browsed 28 Tailwind input fields. Untitled UI Pro unlocks 5,000+ components and sections and 250+ page examples for React, styled with Tailwind CSS v4. One licence is a one-time $349 with lifetime updates; teams start at $999.
The canonical floating label, and the demo that teaches the whole collection: peer on the input, peer-focus: and peer-[:not(:placeholder-shown)]: on the label. The CSS original writes two selector blocks that live nowhere near the label; here the label owns both of its lifted states.
A hairline underline that draws outward from the centre on focus. The whole effect is one element and one variant: an after: bar pinned at left-1/2 right-1/2, released to focus-within:after:inset-x-0.
Cyan neon for dark dashboards and developer tools: a translucent cyan border on near-black, and three layered shadows that bloom together on focus. The layered shadow is one arbitrary utility — exactly the case Tailwind is not trying to tokenise.
A frosted field floating over a blurred gradient. backdrop-blur-[20px] backdrop-saturate-150 does the frost, isolate traps the -z-10 backdrop inside the component, and the inner bevel is one inset shadow.
The Material notched outline — rebuilt on a real <fieldset> and <legend>, so the browser cuts the gap for you. The CSS original fakes it with three bordered spans and an opaque label background that must exactly match the page; this version works on any surface, gradient included.
Four background layers, one per edge, animating from zero to full length on a staggered delay chain — the stroke draws around the field on focus. No keyframes, no SVG, no @property: only background-size moves.
Newsletter
Enjoying these demos? Get new ones by email.
A short email when a new collection ships. Unsubscribe any time.
Live valid/invalid feedback with zero JavaScript, graded on :user-valid and :user-invalid rather than :valid/:invalid — so the field is never marked wrong before it has been touched. That is the gotcha the CSS original lists and does not fix.
A pill search field with a leading magnifier and a trailing clear button that only exists when there is something to clear. type="reset" does the clearing; has-[input:placeholder-shown]: does the hiding.
A live strength bar graded from native constraints alone — minlength and a character-class pattern, read through group-has-[…] into four bar widths. No scoring library, no script.
Six single-character boxes in a <fieldset>, with auto-advance, backspace step-back and paste-to-fill. autocomplete="one-time-code" on the first box is what surfaces the iOS SMS suggestion.
The native placeholder attribute itself cycles through four sample queries every 2.5 seconds, fading between them. The script swaps one attribute and flips one data attribute; every visual is a utility, and rotation pauses the instant the user focuses.
Type a tag, press Enter or comma, get a chip. Backspace on an empty input removes the last one. The chip's whole appearance is a single class string in the script — the one place a port has to put utilities in JavaScript, and worth seeing.
A native <select> for the dialling code welded to a type="tel" field inside one focus ring. Semantic by default: the select is a real select, so iOS gives you the wheel and screen readers give you a listbox.
A quantity control with custom −/+ buttons over a real type="number", so keyboard arrows, validation and form serialisation survive. The CSS original's script reads the wrong dataset key and never steps at all — fixed here.
Newsletter
Enjoying these demos? Get new ones by email.
A short email when a new collection ships. Unsubscribe any time.
Drag-and-drop upload with a dashed boundary and zero JavaScript: a real file input stretched invisibly over the whole zone, so the browser handles the drop, the picker and keyboard focus. A 0 KB replacement for Dropzone.js in the common single-file case.
Right-aligned money with an inline $ that lights up on focus. tabular-nums keeps digit widths locked as the user types — the detail that makes a column of amounts stop shimmering.
A styled type="date" that keeps every native affordance — keyboard entry, locale, min/max, the OS calendar — while the closed field matches your form. scheme-dark and accent-* are both real v4 utilities, which is most of the work.
Two type="time" fields grouped in a <fieldset> with an arrow between them: one visual unit, two independently submittable values. Quiet hours, shift windows, appointment ranges.
A native colour swatch welded to a hex field — and, unlike the CSS original, the two actually talk to each other. Twelve lines of JavaScript keep swatch and text in sync both ways, which is the entire point of showing them together.
A search field with a mic that pulses while listening. The recording state is aria-pressed on a real button, and every visual — icon colour, halo, pulse — is a variant reading that attribute, so the accessible state and the visible state cannot disagree.
Type @ and the common domains appear in a keyboard-navigable listbox. A full ARIA combobox — aria-expanded, aria-controls, aria-activedescendant, role="option" — with the selected row styled by aria-selected: rather than a class.
A textarea that grows with its content and shrinks back — one utility, field-sizing-content, replacing the ResizeObserver-and-hidden-mirror dance every form library used to ship.
Newsletter
Enjoying these demos? Get new ones by email.
A short email when a new collection ships. Unsubscribe any time.
Click-to-edit text that swaps a display span for an input, saves on Enter or blur and cancels on Escape. The editing state is a data-editing attribute on the wrapper, so the border, background and pencil all read it as a variant.
A native type="range" with a painted fill and a live value chip. The script writes one custom property; the gradient and the chip both read it — so dragging touches a single number, not a stylesheet.
A URL field with a fixed https:// badge welded to its left edge: users type the host, you join the protocol on submit. The CSS original's pattern carries eight backslashes and matches nothing — fixed here.
Auto-formatted card number with brand-aware accent. The brand lives in a data-brand attribute and every colour reads it as a variant — and unlike the original, reformatting no longer throws your caret to the end of the field.
An eye button that swaps type="password" for type="text", with the icon swap driven entirely by aria-pressed. Role, name and state change in lockstep — WCAG 4.1.2 satisfied by construction rather than by discipline.
A hard 2.5px border, zero radius and a flat offset shadow that the field presses into on focus. The whole aesthetic is four utilities, and the RTL flip the CSS original leaves as a gotcha is one rtl: variant here.
FAQ
Frequently asked questions
Why does my Tailwind floating label never drop back down when the input is empty?
The floating label rides on Tailwind's peer mechanic, not JavaScript. Mark the <input> as peer, then style the sibling <label> with peer-placeholder-shown: for the resting state and peer-focus: for the raised state. The label reads the input through :placeholder-shown, which is only true while the field is empty. The bug almost everyone hits: the label never returns to its resting position because the input has no placeholder attribute at all. :placeholder-shown can only match when a placeholder exists, so give the input a placeholder of a single space (placeholder=" "). Keep the label after the input in source order too — peer-* variants only reach later siblings, never earlier ones, so a label written before the input will never respond.
How do I show validation errors only after the user finishes typing, not on page load?
Demo 07 grades the field with :user-valid and :user-invalid rather than :valid and :invalid, and that distinction is the whole point. Plain :invalid matches the moment the page loads — a required email field is invalid while empty, so a red border and error message flash before the user has typed a single character. :user-invalid only matches after the user has interacted with and left the field, so feedback arrives when it is actually useful. Wire it with arbitrary variants: [&:user-valid]:border-green-500 and [&:user-invalid]:border-red-500. The same approach drives the Demo 09 strength meter, graded purely from minlength and a character-class pattern. The trade-off is reach: :user-valid is newer than :valid, so on an older engine the styling simply does not apply and the field stays neutral — a safe fallback rather than a broken one.
How does the OTP input auto-advance and still support pasting a code?
The six-box OTP in Demo 10 groups its inputs in a <fieldset> with a <legend> so assistive tech announces one labelled group instead of six anonymous boxes. Each box uses inputmode="numeric" and maxlength="1", and the first carries autocomplete="one-time-code" so mobile keyboards offer the code straight from SMS. The script does three things: it advances focus to the next box on input, steps back to the previous box on Backspace when the current one is already empty, and spreads a pasted string across every box at once. That last part is the common bug — if you only listen for keystrokes, a user pasting a six-digit code fills box one and drops the other five, because paste is a single event, not six keypresses. Listen for the paste event, split the pasted text, and distribute one character per box.
Can I make a textarea grow with its content without a scroll-height script?
Demo 22 replaces the usual scroll-height JavaScript with one CSS declaration — field-sizing: content, which Tailwind writes as field-sizing-content. The <textarea> then measures its own content and grows and shrinks to fit, with min-h and max-h utilities capping the range. There is no input handler, no hidden mirror element, and no layout thrash from reading and writing heights every keystroke. When should you not reach for it? Browser support is the catch: field-sizing is a recent property, so on an engine that lacks it the textarea falls back to a fixed height and simply scrolls. That is graceful degradation, not the effect you designed. If auto-grow is essential on every browser you must support, keep the classic scroll-height script; if it is an enhancement over a perfectly usable fixed-height field, the one-line CSS version is far less code to carry.
How is the Material notched outline built, and is it accessible?
The notched outline in Demo 05 is not a fake gap punched into a border image — it is a real <fieldset> whose <legend> holds the label. A legend inside a fieldset naturally interrupts the top border, which is exactly the notch the Material look wants, so the browser draws the gap for free and it tracks the label's width automatically as the text changes. On focus the fieldset border colour and width change while the legend shrinks and rises. Because the markup is a genuine grouping element, the field is announced with its label correctly. The gotcha is naming: a legend labels the group, not the control inside it, so the <input> still needs its own accessible name. Pair it with an associated <label> or an aria-label rather than relying on the legend alone, or some screen readers will read the input as unlabelled.
How does the file drop zone work without any JavaScript, and what are its limits?
Demo 15 gets drag-and-drop upload with zero JavaScript by stretching a real <input type="file"> invisibly across the whole drop area. The input is set to opacity-0 and absolute inset-0 so it fills the dashed boundary; the styled panel beneath is what the user sees. Because a native file input already accepts clicks, dropped files, and keyboard focus, you inherit the OS picker, drag-and-drop, and tab order without a line of script. The bug to watch is stacking order: if any decorative layer sits above the input, clicks and drops stop reaching it, so keep the input last in the stack or give it a higher z index. What you cannot do in CSS alone is show the dropped file's name or a thumbnail — the native control does not expose that to styling — so add a small script listening for change if you need file-name feedback after a drop.
What accessibility details does a password show/hide toggle need?
The eye control in Demo 27 swaps the field between type="password" and type="text". Make it a real <button type="button"> — not a <div> with a click handler — so it is keyboard reachable, and expose the current state with aria-pressed so a screen reader announces whether the password is visible. Because the button is icon-only it needs an aria-label such as Show password, updated to Hide password when toggled. The classic bug is omitting type="button": inside a <form> a button defaults to type="submit", so clicking the eye submits the form and reloads the page mid-entry. Keep focus on the button after toggling, too — changing the input's type must not blur the control or move the caret, or a keyboard user loses their place.
When should I build a full ARIA combobox instead of using a native datalist?
Demo 21's email combobox is a full ARIA pattern, not a styled <datalist>. The input carries role="combobox", aria-expanded, and aria-controls pointing at a role="listbox"; each suggested domain is a role="option", and arrow keys move aria-activedescendant so focus stays in the input while the visual highlight walks the list. Enter accepts the active option, Escape closes it. Build this only when you genuinely need custom rendering, grouping, or filtering. If a plain list of allowed values is all you want, a native <datalist> gives you the dropdown, keyboard support, and accessibility for a fraction of the code and no ARIA to keep in sync. The combobox's common bug is exactly that syncing — forgetting to update aria-expanded or aria-activedescendant leaves assistive tech announcing a closed list or the wrong highlighted option.