8 Copy-Paste Form Input Snippets That Make Native Controls Feel Custom-Built

8 free form input snippets — iOS toggle, floating labels, OTP input, password strength meter & more. Copy-paste HTML/CSS/JS, export to React/Vue.

8 Copy-Paste Form Input Snippets That Make Native Controls Feel Custom-Built

Forms are where products win or lose users — sign-ups, checkouts, settings pages — and yet the default browser controls still look like they shipped with Windows XP. The fix isn't a component library; almost every polished input you've admired is a native control restyled with a few CSS tricks. Below are 8 free form snippets — an iOS-style toggle, floating labels, an animated checkbox, a six-box OTP input, a live password strength meter — you can preview live and copy in seconds. Pure HTML, CSS and a few lines of JS, no framework required.

As with every roundup in this series, this isn't just a copy-paste dump. For each snippet you'll find how it actually works under the hood, when to reach for it, and a quick tip for customising or keeping it accessible. By the end you'll know the small toolkit — the hidden-checkbox pattern, :placeholder-shown, :focus-within, SVG stroke-dashoffset, focus-management JS — behind nearly every custom form control on the modern web.

Every snippet below is a live, interactive preview — click, type and tab through it right in the article. When you find one you like, hit View / Edit Code to grab the HTML/CSS/JS or export it to React, Vue, Angular or Tailwind.

The golden rule: style the control, keep the input

Custom form controls have a famous failure mode: developers replace the native <input> with styled divs and throw away everything the browser gave them for free — keyboard support, focus management, form submission, screen reader semantics. The snippets below all follow the same golden rule instead:

  • The native input stays in the DOM — hidden with opacity: 0 and zero size, never display: none, so it keeps receiving focus, keyboard events and form data.
  • CSS state selectors do the styling:checked, :focus-visible, :placeholder-shown and sibling combinators restyle the visible element based on the real input's state.
  • Labels do the clicking — wrap the control in a <label> and the browser wires up the hit area for you, no click handlers needed.

Get this pattern once and you can build almost any custom control. Now the snippets.

1. Toggle Switch — the iOS switch in pure CSS

How it works: the golden rule in its purest form — zero JavaScript. A real <input type="checkbox"> hides inside a <label> with opacity: 0 and no size. The visible pill is a sibling span; its knob is an ::after pseudo-element. Two selectors do everything: input:checked ~ .track turns the pill indigo, and input:checked ~ .track::after slides the knob across with transform: translateX(20px). Clicking the label toggles the real checkbox, keyboard users can Space it, and a form submit picks up the value — the browser does all the work.

When to use it: single on/off settings — dark mode, notifications, auto-save. Toggles read as "takes effect immediately"; checkboxes read as "part of a form I'll submit" — pick accordingly. Tip: the snippet includes a small size variant done entirely by overriding track and knob dimensions, so one component covers dense settings lists too.

Try it: Toggle Switch

2. Floating Label Input — the Material trick in 3 selectors

How it works: the label starts as fake placeholder text, vertically centred over the input, then shrinks and floats to the top border the moment you focus or type. The whole effect is one CSS trick: the input gets placeholder=" " — a single space — which makes :placeholder-shown a reliable "is this field empty?" test. The selector input:not(:placeholder-shown) ~ label, input:focus ~ label then moves the label up, shrinks it to 11px and colours it indigo. A white background on the label lets it sit cleanly on top of the border line. No JavaScript, no wrapper classes to manage.

When to use it: sign-up and login forms where vertical space is tight — the label and placeholder occupy the same pixels instead of stacking. Tip: keep the label short. A floating label truncates awkwardly at small size, and it can't hold hint text — put format hints ("DD/MM/YYYY") below the field instead.

Try it: Floating Label Input

3. Custom Checkbox — a checkmark that draws itself

How it works: same hidden-input pattern as the toggle, but the payoff is the tick. The checkmark is an SVG polyline whose stroke-dasharray and stroke-dashoffset are both set to the path's length (24), which renders it invisible. On input:checked, the offset transitions to 0 and the tick draws itself stroke-first, like a pen — the same dashoffset maths as a progress ring, applied to a 3-line icon. The box also gets press feedback (:active scales it to 0.9) and a proper keyboard focus ring via :focus-visible, plus a styled disabled state.

When to use it: everywhere you currently have a native checkbox — consent boxes, preference lists, filters. It submits and validates exactly like the native control because it is the native control. Tip: the 0.05s transition delay on the tick matters — it lets the box's background fill first, so the draw reads as a two-beat animation instead of a blur.

Try it: Custom Checkbox

4. OTP / PIN Input — six boxes that behave like one field

How it works: six single-character inputs with inputmode="numeric" (mobile keyboards open the number pad), glued together by three small event handlers. On input: strip non-digits with a regex and auto-focus the next box. On keydown: if Backspace is pressed in an empty box, jump focus back to the previous one — the detail that makes deleting feel natural. And on paste: intercept the clipboard, strip non-digits, distribute one character per box, and land focus after the last filled digit — so pasting a code from an SMS or email just works.

When to use it: verification codes, 2FA, payment PINs. Separate boxes communicate "exactly 6 digits" better than any helper text. Tip: the paste handler is the difference between a delightful OTP field and a rage-inducing one — test it first when evaluating any OTP component, because most implementations get it wrong.

Try it: OTP / PIN Input

5. Password Strength Meter — live feedback as they type

How it works: on every keystroke, four regex tests run against the value — length ≥ 8, an uppercase letter, a digit, a symbol — and the count of passes becomes a 0–4 score. That one number drives everything: how many of the four segment bars fill, which colour they take (red → amber → indigo → green), the "Weak / Fair / Good / Strong" label, and which items in the requirements checklist flip from a hollow circle to a filled green dot. A show/hide eye button toggles the input between type="password" and type="text".

When to use it: any "create password" field. Live requirement feedback kills the most frustrating form experience on the web — submitting, failing, and only then learning the rules. Tip: segmented bars beat a single continuous bar because they map one-to-one to the rules; users can see exactly which requirement is missing rather than guessing why the bar is stuck at 60%.

Try it: Password Strength Meter

6. Star Rating — hover preview, click to commit

How it works: five stars, each carrying a data-v value from 1 to 5, and one comparison doing all the visual work: on hover, classList.toggle('active', starValue <= hoveredValue) lights every star up to the cursor. Click stores the value in a selected variable; mouseleave on the container restores the display to the committed rating (or grey if none). A label swaps between "Poor / Fair / Good / Great / Excellent!" as you move, so the rating has words, not just symbols.

When to use it: reviews, feedback prompts, NPS-style surveys. The hover-preview / click-commit / leave-restore trio is the pattern users expect from every rating widget they've used. Tip: to submit the value with a form, mirror selected into a hidden input on click — one line, and your backend sees a normal form field.

Try it: Star Rating

7. Tag / Chip Input — the multi-value field done properly

How it works: the "field" is actually a flex-wrap container holding chip elements plus a borderless text input that flexes to fill the remaining space — clicking anywhere in the container focuses the input, and :focus-within draws the focus ring on the container so the whole thing behaves like one field. Enter or comma commits the current text as a chip (after trimming and rejecting duplicates), each chip carries its own × button, and new chips pop in with a quick scale animation. A row of suggestion buttons demonstrates programmatic adds.

When to use it: skills, categories, email recipients, filters — any input that's really a list. Chips make each value individually removable, which beats asking users to edit a comma-separated string. Tip: :focus-within is the unsung hero here — without it the inner input focuses invisibly and the field looks dead while the user is typing in it.

Try it: Tag / Chip Input

8. Multi-step Form — one form, three screens, zero page loads

How it works: all three steps live in the DOM at once; a single cur variable decides which panel has the .active class (shown, with a slide-in animation) while the rest stay display: none. The progress header — numbered dots joined by connector lines — is driven by the same variable: dots behind you get a filled "done" state, the current dot gets the outlined active state, and the connector lines fill as you pass them. The Back button hides itself on step one and the Next button becomes the finish action on the last step.

When to use it: onboarding, checkout, anything longer than five fields. Splitting a long form into steps raises completion rates for one simple reason: a form that shows three fields feels finishable, one that shows fifteen doesn't. Tip: validate each step at the Next click, not at the end — sending a user back two screens to fix an email typo undoes all the goodwill the wizard earned.

Try it: Multi-step Form

The techniques you just collected

Eight controls, five reusable ideas — learn these and you can restyle nearly any form element without a library:

  • The hidden-input pattern — keep the native control invisible but alive, style a sibling with :checked. Powers the toggle and the checkbox, and it's why both work with keyboards and form submits for free.
  • :placeholder-shown as an "is empty" test — the one-space placeholder trick behind every floating label.
  • :focus-within on containers — makes composite fields (chips, OTP groups) light up as one control while a child input holds real focus.
  • SVG stroke-dashoffset reveals — set the dash to the path length, transition the offset to zero, and any icon draws itself. Powers the checkbox tick.
  • Focus choreography in JS — moving focus for the user (OTP auto-advance, backspace-to-previous, click-to-focus containers) is what makes multi-part inputs feel like single fields.

Final Thought

Here's a challenge for your next project: before you npm install a form library, try building the controls from these eight patterns instead. You'll ship less JavaScript, you'll actually understand your own form when it breaks, and — the part nobody expects — the native-input-plus-CSS version is usually more accessible than the library, not less, because the browser is doing the hard parts.

Every snippet here is part of the free form snippets collection at FWD Tools, alongside range sliders, credit card inputs, file dropzones and colour pickers that didn't make this list — all editable in the browser and exportable to React, Vue, Angular or Tailwind. Earlier roundups in this series cover buttons, hover cards, text effects and loading states.

About the author

Puneet Sharma
Puneet Sharma is a freelance web developer, tech writer, and founder of FWD Tools. He publishes WebDevPuneet, TheTechWatcher, TheAutoWatcher, HollyWatcher, and BollyWatcher.

Post a Comment