Group digits four-by-four. Inserting a space every four characters turns an unreadable 16-digit run into scannable chunks like 4242 4242 4242 4242.
The leading digit names the brand — 4 is Visa, 5 is Mastercard, 3 is Amex. Surface the matching card mark inline as the user types.
When you auto-insert a separator, keep the caret right after the character just typed. Jumping it to the end of the field is disorienting and breaks editing.
Validate on blur, not on keystroke. Flagging "Invalid card" while someone is mid-entry reads as premature; stay neutral until they leave the field, then confirm success.
Strip junk on paste. When a value arrives with dashes or spaces, clean it and reformat to your own grouping instead of rejecting it.
Show formatted, store raw. Render the grouped value for the user, but persist the unformatted digits (no spaces or dashes) as the stored value.
Do / Don't
Do: Group long numbers into fixed chunks so they stay readable as they're typed
Do: Detect the card brand from the leading digit and show its mark inline
Do: Reformat pasted values instead of erroring on their separators
Don't: Let the caret jump to the end when a separator is auto-inserted
Don't: Flag a validation error on the first keystroke instead of waiting for blur
Don't: Save the formatting characters with the value — keep the stored data raw
The Design System Blueprint
An 11-page visual guide to consistent, scalable UI: colors, typography, spacing, components, motion.