Key insights
- 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