GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

CSS Input Design: 9 Form Widgets You Can Paste In

CSS input design means the small form fields — phone numbers, card numbers, quantities, tags — that fill checkout and signup forms but need a little JavaScript

Five of the nine (tags, auto-grow, drag-drop, resend timer, inline validation) rarely show up in animation libraries — you mostly meet them on real product screens instead.

Auto-plays · click a tile to jump to its section · all nine in one zip

The nine pieces of css input box design are ordered by how a form actually gets filled out, not by popularity: contact and payment details first (01–03), quantity and tags next (04–05), notes and attachments after that (06–07), and identity verification plus final validation last (08–09). Narrow it down to six digit boxes and you get OTP Input UI; line the same fields up on a signup screen and you get Register Form Design.

# Widget When you'd use it
01 Auto-hyphen phone number Signup contact, shipping phone
02 Card number 4-digit grouping Checkout card field
03 Currency input with auto comma Donation, quote amount
04 Quantity +/- stepper Cart quantity, booking guests
05 Tag input Keywords, multiple recipients
06 Auto-growing textarea Review, support message
07 Drag-and-drop file dropzone Profile photo, attachments
08 OTP resend timer button Phone or email re-verification
09 Inline input validation Email, password validation

01Auto-hyphen phone number

What changes in a css input field design

Type digits only and hyphens land in the right spot automatically, like 010-1234-5678.

Auto-hyphen phone number
Open in a new tab

01 · Auto-hyphen phone number — Measured area 0.857% · moving frames 15/23Original by GODRICH · SCSS and React ship in the zip · See the password

010 패턴자동 하이픈숫자만

Where to look in the code

Pasting a full number reformats it the same way.

function format(raw) {
  const d = raw.replace(/\D/g, "").slice(0, 11);
  if (d.length < 4) return d;
  if (d.length < 8) return d.slice(0, 3) + "-" + d.slice(3);
  return d.slice(0, 3) + "-" + d.slice(3, 7) + "-" + d.slice(7);
}
input.addEventListener("input", () => {
  input.value = format(input.value);
});

02Card number 4-digit grouping

What happens on screen

A space is inserted every four digits as you type, so the number reads like a real card.

Card number 4-digit grouping
Open in a new tab

02 · Card number 4-digit grouping — Measured area 1.293% · moving frames 22/23Original by GODRICH · SCSS and React ship in the zip · See the password

4자리 그룹16자리 제한숫자만

How to read the code

The first digit also flags VISA, Mastercard, or AMEX.

function format(raw) {
  const d = raw.replace(/\D/g, "").slice(0, 16);
  const groups = d.match(/.{1,4}/g) || [];
  return groups.join(" ");
}
function brandOf(d) {
  if (d[0] === "4") return "VISA";
  if (/^5[1-5]/.test(d)) return "Mastercard";
  return "";
}

03Currency input with auto comma

What moves

Type digits into a currency-prefixed field and thousands separators appear automatically.

Currency input with auto comma
Open in a new tab

03 · Currency input with auto comma — Measured area 0.557% · moving frames 12/23Original by GODRICH · SCSS and React ship in the zip · See the password

₩ 접두어천 단위 콤마우측 정렬

What to change

Leading zeros are stripped along the way.

function format(raw) {
  const d = raw.replace(/\D/g, "").replace(/^0+(?=\d)/, "").slice(0, 12);
  return d ? Number(d).toLocaleString("en-US") : "";
}
input.addEventListener("input", () => {
  input.value = format(input.value);
});

04Quantity +/- stepper

What you see

Each tap changes the number in the middle by one, and the minus button dims and stops responding once the minimum (1) is reached.

Quantity +/- stepper
Open in a new tab

04 · Quantity +/- stepper — Measured area 0.676% · moving frames 12/23Original by GODRICH · SCSS and React ship in the zip · See the password

최소/최대 제한키보드 지원숫자 직접 입력

Where to look in the code

const MIN = 1, MAX = 99;
function set(v) {
  n = Math.min(MAX, Math.max(MIN, v));
  value.value = n;
  minus.disabled = n <= MIN;
  plus.disabled = n >= MAX;
}
minus.addEventListener("click", () => set(n - 1));
plus.addEventListener("click", () => set(n + 1));

05Tag input

What happens on screen

Type text and press Enter to turn it into a pill-shaped tag; pressing Backspace on an empty field removes the last tag.

Tag input
Open in a new tab

05 · Tag input — Measured area 21.44% · moving frames 19/23Original by GODRICH · SCSS and React ship in the zip · See the password

Enter로 추가×로 삭제백스페이스 삭제

How to read the code

input.addEventListener("keydown", (e) => {
  if (e.key === "Enter" || e.key === ",") {
    e.preventDefault();
    if (input.value.trim()) tags.push(input.value.trim());
    input.value = "";
    render();
  } else if (e.key === "Backspace" && !input.value && tags.length) {
    tags.pop();
    render();
  }
});

06Auto-growing textarea

What moves

As lines are added, the box itself grows taller instead of scrolling, only switching to a scrollbar past a set max height (132px).

Auto-growing textarea
Open in a new tab

06 · Auto-growing textarea — Measured area 36.821% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

scrollHeight 기반최대 높이 제한리사이즈 불가

What to change

function resize() {
  // reset to auto first, or the height never shrinks back down
  area.style.height = "auto";
  const next = Math.min(area.scrollHeight, 132);
  area.style.height = next + "px";
}
area.addEventListener("input", resize);

07Drag-and-drop file dropzone

What you see

Dragging a file over the zone thickens its border, and dropping it turns the filename into a chip.

Drag-and-drop file dropzone
Open in a new tab

07 · Drag-and-drop file dropzone — Measured area 26.096% · moving frames 10/23Original by GODRICH · SCSS and React ship in the zip · See the password

dragover 표시클릭해서 찾아보기키보드 접근

Where to look in the code

Clicking still opens the normal file picker.

zone.addEventListener("dragover", (e) => {
  e.preventDefault();
  zone.classList.add("is-over");
});
zone.addEventListener("drop", (e) => {
  e.preventDefault();
  zone.classList.remove("is-over");
  const file = e.dataTransfer.files[0];
  if (file) filename.textContent = "Selected: " + file.name;
});

08OTP resend timer button

What happens on screen

Tapping resend disables the button for 60 seconds while the remaining count ticks down on the button label itself, then re-enables at zero.

OTP resend timer button
Open in a new tab

08 · OTP resend timer button — Measured area 3.449% · moving frames 15/23Original by GODRICH · SCSS and React ship in the zip · See the password

60초 카운트다운중복 클릭 방지aria-live 안내

How to read the code

function cooldown(seconds) {
  let left = seconds;
  btn.disabled = true;
  btn.textContent = left + "s to resend";
  const t = setInterval(() => {
    left--;
    if (left <= 0) {
      clearInterval(t);
      btn.disabled = false;
      btn.textContent = "Resend";
    } else {
      btn.textContent = left + "s to resend";
    }
  }, 1000);
}

09Inline input validation

What moves

While typing, a green check appears the moment the email format is valid, or a red message if it isn't.

Inline input validation
Open in a new tab

09 · Inline input validation — Measured area 3.935% · moving frames 14/23Original by GODRICH · SCSS and React ship in the zip · See the password

실시간 검증role="status" 알림성공/실패 아이콘

What to change

An empty field shows nothing at all.

const RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
input.addEventListener("input", () => {
  const v = input.value;
  frame.classList.remove("is-ok", "is-bad");
  if (!v) { icon.textContent = ""; msg.textContent = ""; return; }
  if (RE.test(v)) { frame.classList.add("is-ok"); icon.textContent = "✓"; }
  else { frame.classList.add("is-bad"); icon.textContent = "!"; msg.textContent = "Check the email format"; }
});

Where this breaks — one real trap

01, 02, and 03 all share the same trap. Whenever you rewrite input.value wholesale, like input.value = format(value), the browser resets the caret to the very end of the string. Click into the middle of an already-formatted number to fix a digit, and the next keystroke sends the caret flying back to the end anyway. For short phone or card numbers this barely matters, but for anything you expect people to edit at length, MDN's HTMLInputElement.setSelectionRange docs show how to save the caret position before reformatting and restore it after. When typing gives way to picking, 9 Date Range Picker UI Patterns takes the next widget slot. The password for the zip holding all nine files — working vanilla JS and a React version each — is puc8udvv — grab it with the button below.

07's drag-and-drop hides a similar gotcha. Skip calling preventDefault() on the dragover event and the browser falls back to its default behavior (opening the file in a new tab), which means drop never fires at all. The snippet above handles that on purpose.

Accessibility

Every field pairs a label with its input through for, and 04's stepper announces the new count ("Quantity 3") through a visually hidden aria-live region so screen reader users hear the change without seeing the number. 08's resend button reports completion through an aria-live="polite" status line, and 09's validation message uses role="status" so it updates quietly only when the value actually changes. 07's file input stays reachable by Tab and opens the native picker with Enter or Space, so the whole flow works without a mouse. Every color and border transition also honors prefers-reduced-motion, per MDN's docs.

@media (prefers-reduced-motion: reduce) {
  .field__input, .drop__zone, .valid__frame { transition: none; }
}

More form-input pieces live in OTP Input UI: 9 States, and the about page explains what this site is for.

FAQ

Can I drop these nine straight into a React project?

Yes. The zip's react/ folder has a .tsx and a .module.scss for every item, ported from the same logic as the vanilla JS in vanilla/. You mostly just pass in a color or label string as props.

Does auto-formatting the card number affect payment security at all?

No. What's shown here only groups digits into a readable 4-digit pattern on screen — actually handling or storing card data is the payment processor's job, and this formatting never sends anything to a server. Judging each entry as it's typed, right before submit, is the job of 9 Form Validation UI Patterns.

In a css html form design, does the numeric keyboard pop up automatically on mobile for the phone and card fields?

Yes, inputmode="numeric" tells most mobile browsers to show the numeric keypad instead of the full keyboard. It's only a hint though, so behavior can vary slightly between browsers.

Enter the archive password

The password is inside this article. You will find it as you read.