/

React Inputs: Search, OTP, Tags and the AI Prompt Box

Five input shapes with five different contracts, the attributes that decide whether a phone fills the form in one tap, and where validation belongs.

Serafim Korablev
Serafim Korablev
@korablev

The text input is the oldest control on the web and still the one most often shipped broken. Not visually: the border radius is always fine. Broken in the sense that it loses what you typed on autofill, refuses the format you use, opens the wrong keyboard on a phone, or has no label at all because the placeholder was doing the job.

The catalogue splits inputs by the shape of the value rather than by the look, and that split is where the useful decisions are.

The plain field, done properly

Input by berlix is the base. Everything worth saying about it is in the attributes, and they are worth saying because they are what most implementations skip.

A real <label>, always. A placeholder is not a label: it disappears the moment someone types, which means anyone who is interrupted has lost the question. If the design has no room for a visible label, it still needs one in the DOM, visually hidden.

autocomplete with the right token. email, given-name, street-address, one-time-code. This is what makes a password manager and a browser fill the form correctly, and getting it wrong is the difference between one tap and three minutes on a phone.

inputmode and type for the keyboard. inputmode="numeric" for a code, type="email" for an address, type="search" for a search box. Wrong keyboard is the most common mobile complaint that nobody reports.

Never suppress the format. If the field wants a phone number, accept spaces, dashes and brackets and normalise afterwards. Rejecting "+44 20 7946 0958" because of the spaces is a bug the reader will blame themselves for.

The search input

Its own component because its behaviour is different: it filters as you type, it needs a clear button, and it has to survive being typed into fast.

Expanding Search Dock by Moumen Soliman is a search icon that expands into a full input with a blur behind it, and Animated Search Bar by Erik X is the same idea with different motion.

Two rules. Debounce the request, not the input: the field should update instantly and the network call should wait 200 to 300ms. And announce the result count in a live region, or a screen reader user types into a box and hears nothing change.

A note on the expanding pattern: it saves space and costs discoverability. On a page where search is the primary action, keep the field open.

The one-time code

OTP Verify by Le Thanh, Input OTP by jshguo and BeUI OTP Input by Saurabh Chauhan are the segmented-box pattern.

This is the component where a small detail changes the whole experience: autocomplete="one-time-code" lets iOS and Android offer the code from the SMS directly above the keyboard. Without it, the reader switches apps, memorises six digits and switches back. Also handle paste across all boxes at once, because everyone pastes.

The tag input

Input With Tags by Chetan Verma is the chips-in-a-field pattern for lists of values: recipients, labels, skills.

The keyboard contract is the part that gets missed. Enter and comma commit a tag, Backspace on an empty field selects the last chip rather than deleting it silently, each chip has its own remove button with an accessible name, and the whole set is announced as a group.

The prompt box

The newest shape in this category and now one of the most requested: a textarea that grows as you type, sends on Enter, keeps a new line on Shift-Enter, and carries attachments, a model picker and a stop button.

Placeholders And Vanish Input by Manu Arora is the marketing version, with placeholders that slide in and a vanish effect on submit. The functional ones live with the chat components, and the AI chat guide covers the composer in detail.

The trap specific to this shape: auto-resize implemented by measuring scrollHeight on every keystroke forces a layout on every keystroke. Use field-sizing: content where it is supported, or a hidden mirror element, and cap the height so a long paste does not swallow the screen.

Where validation belongs

Errors go next to the field, not in a toast, and they arrive on blur rather than on the first keystroke. Nothing is more hostile than a field that turns red while you are still typing the third character of your email address.

Once a field has been marked invalid, switch it to validating on change, so the error clears as soon as the reader fixes it. Mark it with aria-invalid and point aria-describedby at the message, so the error is read out with the field rather than discovered by accident. And on submit, move focus to the first invalid field: a form that fails silently at the bottom of a long page is a form nobody completes.

Where else to look

The honest list of alternatives, because the answer is not always us:

SourceBest forTrade-off
shadcn/uiInput, Textarea, InputOTP and Label with the wiring correctPlain by design; no tag input, no search behaviour
React Hook Form + ZodValidation, error state and submit handlingNot a visual layer
React AriaNumber, date, tag and search fields with the announcements handledMore API, and you still write the visuals
21stExpanding search, tag fields, OTP boxes and prompt composersQuality varies by author, so preview before you take it

Taking one

Every component page has a live preview and the code. Installing goes through the shadcn CLI against our registry:

bash

That key comes from your 21st account, and installs require a membership. Set API_KEY_21ST once in your shell and the command works for anything in the catalogue. The 21st MCP covers the same ground without leaving the editor: ask Claude, Cursor or Codex for an input, get the previews inline, and let the agent write the file.

Browse input components →

Frequently asked

Can a placeholder replace a label?
No. A placeholder disappears the moment someone types, so anyone interrupted has lost the question, and it fails contrast in most designs. If the layout has no room for a visible label, keep a real label element in the DOM and hide it visually. The label is also what makes tapping the text focus the field.
Which input attributes actually matter?
autocomplete with the correct token, which is what lets a browser or password manager fill the field; inputmode and type, which decide the on-screen keyboard; and a real label. Getting autocomplete wrong is the difference between one tap and three minutes of typing on a phone, and it is invisible on a desktop where most testing happens.
How do you build an OTP input properly?
Segmented boxes are the easy part. The detail that changes the experience is autocomplete="one-time-code", which lets iOS and Android offer the code from the SMS directly above the keyboard. Handle paste across all boxes at once, because everyone pastes, and keep the whole group announced as a single field.
When should a form show validation errors?
On blur, then on change once a field has already been marked invalid, so the error clears as soon as it is fixed. Errors belong beside the field with aria-invalid and aria-describedby pointing at the message, never in a toast in the opposite corner. On submit, move focus to the first invalid field.

Published

Aug 20, 2026

Read time

6 min

Tags

GuideFormsReactAccessibility

Share