
Cleave.js – Format input text content when you are typing - octosphere
https://nosir.github.io/cleave.js/
======
tlb
When I’m just trying to get past a signup form, please don’t make me re-learn
a new way to type. Here, the delete key does something other than delete the
last keypress. For example, typing 20199<delete>11 gets me 2019/01/1 because
it helpfully autoinserted the 0 before the 9 and didn’t undo it.

Filling in a form is never delightful. It’s a tedious interruption in my flow.
Just let me get past it with minimum cognitive load.

~~~
the_pwner224
On Firefox mobile, the backspace key _can 't_ delete the automatically
inserted slashes. Type in 2019 09 > need to change month from 09 to 02 ->
backspace key just doesn't work -> need to click on the textbox between the 9
and / to position cursor and then press backspace.

Would a normal person try to do that or would they just reload the page and
start the whole form over again? Or would they just leave the website and
never come back?

~~~
folkhack
Usability errors/barriers like this on high-profile sites have caused millions
in lost-revenue.

Many people just abandon their intended action when simple usability things
are not right because your sales experience is sorta a "first impressions"
thing (bit of a generalization but yea).

------
hathawsh
My Google-foo is failing me: isn't there a site that catalogs UX/UI anti-
patterns? This library edits what the user types in real time, which is a
serious anti-pattern because it causes users to compound mistakes. I would
call it the "overzealous autocorrect" antipattern.

For example, if I want to type in the date "2017-03-30", but I accidentally
type "2017-02-30", this library silently changes the day in addition to the
month, leaving me with "2017-02-28". I suppose you could use this to
illustrate how fallible humans are, but if your goal is to minimize errors,
you simply can't autocorrect number fields. You must show error messages.

~~~
pault
I have to deal with exactly this issue at work on a project that emulates
spreadsheet behavior for number formatting. I learned immediately that you
have to format on blur, because anything you do to the input value while the
user is typing will move their cursor to the end of the input, and no amount
of clever prediction will put it back in the right place in all cases. Always
format on blur unless you want your users to hate your app.

~~~
Zarel
You can detect where the cursor is before editing the input value, and place
it in the correct place afterwards. This is a pretty basic trick used in many
different places, including by Cleave itself.

~~~
pault
I think my comment has been validated by the dozens of comments here
complaining about broken inputs. I didn't say it was impossible; the basic
trick only works in simple cases and the edge cases are numerous. If I
implement a feature and it causes even one person to bounce, it's a failure.

~~~
Zarel
Well, yeah, Cleave.js isn't a very usable example, as the dozens of comments
are proving. But it proves that it's _possible_. Your comment is saying that
it's impossible:

> no amount of clever prediction will put it back in the right place in all
> cases

If you're instead changing your argument to say that it's impossible to do
_well_, that's a different argument which I also disagree with: most
implementations of tab-completion definitely have more fans than opponents.
Not to mention keyboard shortcuts like Cmd+I to bold, or Cmd+B to italicize.
Or even OS features like copy/paste. Many features require modifying the
contents of a textbox, and it's far from impossible to do well.

~~~
TeMPOraL
Tab completion is different - it's explicit, you have to _choose_ a
completion. Bolding, italicizing, copying, pasting, etc. are all explicit
actions here.

This here is implicit alteration of user input, and the real question is not
whether it _can_ be done correctly (in this case, I vote for "maaaybe in
theory; impossible in practice"). The real question is why do it _at all_? It
only confuses and irritates people, which makes them make _more_ errors and
also break their flow.

(Hell, it's not an issue if that's just one field on a random sign-up field of
some fly-by-night shop. But those "brilliant" UX ideas tend to find their ways
to software people use for work - say, managing listings in ecommerce shops.
There, such ideas cause many people to lose a lot of time, and by extensions
their employers to lose a ton of money.)

~~~
Zarel
Why do it at all? Because users like the feature, because the grouping numbers
makes typoes easier to spot, etc.

If you want to narrow it down to implicit alteration: Syntax highlighting is
implicit alteration. And people love it.

So are a lot of WYSIWYG features, like Enter inserting a new paragraph or a
new bullet point depending on context. Or tab completion itself, in the sense
that it replaces the "insert tab" feature of the Tab key. Or URLs
automatically transforming into links.

Explicitly with regards to Cleave.js-style auto-formatting, I personally like
it (for the same reason I like syntax highlighting) and I assume many other
users do too. Someone further downthread mentioned an AB test showed improved
conversions:

[https://news.ycombinator.com/item?id=19234805](https://news.ycombinator.com/item?id=19234805)

~~~
TeMPOraL
> _If you want to narrow it down to implicit alteration: Syntax highlighting
> is implicit alteration. And people love it._

That's only a change of formatting that's otherwise inaccessible to the user.
Effects like colors and bold/italics aren't part of the code, users can't and
won't try to insert them manually - they're an extra data channel, orthogonal
to what users type in, and thus free for the application to use.

You want Cleave.js-style implicit? Think automatic autocorrect on Windows and
MacOS. That one generates quite a lot of justified criticism - besides being a
huge annoyance when dealing with proper names, brand names, peoples' names,
addresses, etc., it can create life-threatening situations[0].

> _Someone further downthread mentioned an AB test showed improved
> conversions:_

They did, but I honestly don't buy it - not without knowing much more about
the scope and methodology of the test in question (see my response somewhere
in that thread for details). "A/B test told us that" is the new "I was only
following orders".

\--

[0] -
[https://twitter.com/slatestarcodex/status/944739157988974592...](https://twitter.com/slatestarcodex/status/944739157988974592?lang=en)

------
jacknews
I'm sorry to say this is everything I hate about "modern" UI.

It looks fantastic, but, for example, the YYYY/MM/DD field, I can't just write
19/2/23 or whatever (explicitly entering the delimiting slashes), I have to
follow the prescribed format, 2019/02/23 (oh, ok thankfully 2 gets filled to
02 automatically).

Try 1/20 in the MM/YY field. Doesn't work.

It seems fairly simple to fix; when the user types a delimeter, trust them.

~~~
leeoniya
> Try 1/20 in the MM/YY field. Doesn't work.

i've never seen a card that specified expiration month with a single digit.
google images for "card expiration" does not bring up any examples either. a
placeholder="MM/YY" should make it clear that both are needed.

~~~
jeroenhd
To humans, 01 is the same as 1. To computers, there's two integers separated
by a slash.

While it's true that there's a leading 0 on the card itself, there's no reason
not to just split on the / and convert both sides to integers.

~~~
satokema
It depends on the human. Some humans might interpret "01" as one yes, but
others will see it as a "zero-one".

------
jwr
I hate this idea. Why does every credit form out there have to invent new ways
to "format" credit card numbers and do fancy stuff behind my back? I have to
learn how every form works, because cursor keys, delete, and punctuation no
longer behave like everywhere else.

Invest all the effort into reliable, flexible and intelligent parsing of
whatever the user types in. Even in 2019 I find web forms (banks excel at
this) which complain about "invalid" characters instead of ignoring them.

Incidentally, this idea of "let's improve the standard user interface to make
it easier for ORDINARY PEOPLE" is not limited to web forms. Browser URL fields
are a playground for programmer creativity and I'm regularly baffled by their
behavior: autoselecting the entire input, suggestions completing what I typed
even though I never asked for it, and similar ideas.

~~~
rhizome
Blow into your device's left microphone to use VISA. Blow into the right one
for American Express.

~~~
tardismechanic
Ugh! Please don’t give them new ideas!

------
IgorPartola
I am seeing a lot of criticism of this library in the comments. Does anyone
have better suggestions aside from “just let the user enter ‘fuck you’ for a
date and ‘screw this’ for their phone number”?

I am currently using Cleave for a project where the customer unequivocally
requested this kind of functionality. Specifically I need to implement phone
masking, date masking (no calendar pickers except native mobile ones allowed),
and number and currency validation and masking. Cleave was the least
opinionated library of its kind that I found.

~~~
ttty
If a user is gonna write that and you force him to write a proper number he'll
give you a fake one and you'll waste time sending marketing SMS and calls

~~~
mgbmtl
I agree, however, if the user did want to enter their phone number and they
did not notice a silly error because of how it was entered, then you've lost
an opportunity.

We are seeing this lib as users who get frustrated with marketing forms. There
are other use-cases out there. I work with non-profits, where they may not
have the budget for fancier validation, so this helps a lot.

~~~
IgorPartola
What I am working on is not marketing. Users don’t really have the option of
fake numbers or skipping forms. Not that I want it to be inconvenient. Far
from it.

------
morpheuskafka
Perhaps they should read this:
[https://news.ycombinator.com/item?id=19214035](https://news.ycombinator.com/item?id=19214035)

Phone numbers are something you dial into a phone. They are not a alphabetic
ISO code and then some numbers. Country codes and international dialing codes
are NOT 1:1. North Korea for example has two dialing codes but is one county.
Many island nations share the US's +1. Staphones have their own dialing
prefixes that don't correspond to an ISO country code. With all due respect,
this code is a disaster and it is guaranteed to lead to problems when one of
these many edge cases is hit.

------
humanbeinc
I type in my phone number in and THEN select the country..my number gets
deleted... I hate you now

~~~
acdha
I just noticed the same bug. It’d be a little more tolerable if it auto
detected that e.g. +1 meant US or suggested based on the browser locale rather
than requiring you to scroll a huge list but deleting input is almost always a
mistake.

------
jsf01
This is a weird API for what it’s trying to achieve. Why make every Cleave
instance use a boolean to determine its type + some related other field that
varies based on which type happens to be set to true? Doing it this way
prevents tree shaking from getting rid of all the methods you’re not using. If
instead it was something like:

cleave.Date(...), cleave.Phone(...), etc.

then each of those constructors could implement specific options that are
relevant. As it is now, you could have an onCreditCardTypeChanged() method on
a date input. And if you did it in a manner like I’m proposing, you’d be able
to import just the specific formatters you need, allowing your module bundler
to strip out the rest.

~~~
rounce
Glad I'm not the only one that thought the API was a bit 'interesting'. I was
also wondering what happens when you set `phone`, `date` and `creditCard` to
`true` in the same config and pass it to the constructor? Surely this should
at least be a single field, if not separate classes/prototype chains (as jsf01
mentioned).

------
sriram_malhar
This is very nicely done.

Personally I prefer my data entry to be a simple text field so that I can use
backspace, or clipboard paste, or insert/delete from the middle normally.

Meanwhile, the UI can show its interpretation of what I entered just above the
field. For example, if I enter a date field 2/25, the software could show its
interpretation (02/25/2019) as I type, allowing me to quit typing as soon as
the interpretation is correct. Likewise with credit cards: it isn't a big
problem hitting a space bar to separate, but that's my choice.

In other words, the beautiful formatting is good, but keep the input field and
the eventual rendering of the field separate.

------
ken
Cute, but it looks like it's trying too hard to be clever.

Are you expecting websites to show a giant pop-up menu of 2-letter country
codes to users? Or are you expecting websites to hardcode one country, and
reject phone numbers which don't match that pattern? And what about
extensions?

For dates, most browsers support form type="date" and the like. That's going
to be better than whatever you use here.

For credit cards, it's fine, because 16 decimal digits is a universal
standard. For anything else, it's going to cause as many problems as it
solves.

~~~
leesalminen
American Express cards are 15 digits.

~~~
ken
Ha! Shows what I know. Exceptions abound.

------
systematical
We implemented this recently because a design that was dropped on my desk
called for it, cause you know, marketing people. I was pretty happy with the
library, but after reading some of the reviews on here I think we are going to
have to look into how it plays on some devices and use-cases again.

------
franze
Never write the form lables into the form fields. Chrome Form Autofill is a
common use case for all forms. And you can not QA if everything was put in
correctly if the lables are part of the form.

------
hit8run
Nice lib. Though many of these things should simply be solved by browsers
imho. As developer I simply want to render input with the type of phone and be
good. Let those who provide the operating system/browser handle the details in
a standard way.

------
ulucs
Following the comments posted here, I think the proper way to format input is
to split the transformations into two.

The credit card example gives us purely cosmetic changes and it makes sense to
apply them in real-time so the user receives important feedback. The other
type is the application of strict formatting, like in the date format example.
It's really nice to infer 1992223 as 1992/02/23, but it robs some control from
the user. As we're already inferring what the user is trying to say, we could
show them 1992/2/23 to give them feedback and apply the transformation before
sending the data, thus having the best of both worlds.

------
aboutruby
For credit card and bank accounts, Stripe Elements has some battle-tested
React inputs: [https://stripe.dev/elements-
examples/](https://stripe.dev/elements-examples/)

------
moolcool
Prefix is broken-- put the cursor before the 'P' in the example and press any
letter 6 times

------
tokyodude
Wow, horrible! I tried to select a few characters and copy and paste but it
didn't copy the part I selected. instead it copied everything.

Also if you tell me the format is 00:00:00 then I'm going to type digit digit
colon digit digit colon digit digit but instead you auto inserted the colon
which means now my typing and correcting muscle memory is doesn't match. I
typed 8 characters so it should take 8 key presses to backspace or 8
characters to go left.

Please don't use these on your site

------
iambateman
This looks great! I typically use an individual library to format.

One request I didn’t see: money formatting.

~~~
Klathmon
>One request I didn’t see: money formatting.

Probably for a good reason. Formatting currency should be handled by the i18n
system, because that's what it is.

Take one thousand dollars in US currency, it can be displayed as:

$1,000.00

$10,00.00

$1.000,00

$1,000.00 USD

1,000.00 $

$ 1 000,00

and more. And that's not even counting negative numbers which can change their
display format based on the industry it's used in, let alone the language.

Then add in other currencies in different locales, often the currency symbol
is after the currency, some locales use different spacing, some don't have a
decimal to their currency in common usage, some use the same symbol for
different currencies ($ could mean USD or CAD or more and in some cases that
can be a big mistake) and a LOT more edge cases.

------
jrh206
Couldn't find my country for the phone number (UK). Looked for EN and UK,
eventually discovered it was GB. Hard!

~~~
2T1Qka0rEiPr
[https://en.wikipedia.org/wiki/ISO_3166-2:GB](https://en.wikipedia.org/wiki/ISO_3166-2:GB)
\- we failed :D

~~~
GordonS
So, as a developer I know my country's 2-digit ISO code, and those of plenty
of other countries - the point is, the general population _doesn 't_.

~~~
2T1Qka0rEiPr
Heh, no I wasn't assuming that you didn't know, I guess I was just pointing
out that our ISO code is silly!

------
nmstoker
If they can fix the backspacing issue on Android this will be superb for
things like UK sort codes (NN-NN-NN) which invariably are handled badly for
mobile users (eg the most common case being the switching to alphabet from
numeric keyboard with _each_ pair of digits being in a distinct box)

~~~
teknopaul
I dont understand this. For sort codes why not just type six digits? What do
you get from inserting the dashes?

------
kuon
Just don't, I want simple text fields where I can type without being attacked
by a script. I want my autofill to work properly, I want to be able to copy
paste without any strange behaviour. I want to type the delimiter. And you
should be locale aware, for 2019-02-24 I would type 24.2.19. Of course you
might target only the US market with your form, but the problem is that bad
practices are spreading to global developers.

------
miohtama
This is a half way solution, as you can see a lot of artifacts like when
typing numbers to the time field when it is already full.

The only way to properly address this is to bring this as native HTML5
components. Then different UX paradigms, like desktop and mobile, can properly
handle complex input.

This shows the shortcoming of web UI. You cannot properly address shortcomings
of browsers on low enough layer. It is not an issue for native apps.

------
dceddia
The credit card one is cool, but when I clicked it and Chrome offered to
autofill my credit card, the first thing that popped into my head was "hmm,
this would be a sneaky way to siphon some credit card numbers." Paranoid?
Maybe. It made me ponder how I seem to be growing more suspicious of things on
the modern web though.

~~~
kamikaz1k
Can you elaborate on how you expect them to siphon Credit Card numbers? Are
you speaking of the demo, or are you saying of potential users of the library?

~~~
folkhack
Chrome offered to auto-fill his CC number that is stored with his expiry, name
on card, and (maybe) payment address/zip... everything but the CVV, (card
verification number, usually three digits).

Chrome is pretty clever these days with payment details and tries to help you
keep a "wallet" so-to-speak which acts like an "autofill" feature. Do some
searches around Web Payments, Payment Request API, W3C Payment Request, blah
blah - let's just say it goes a lot deeper than basic autofill =)

Now for siphoning. That attack (as far as I know) wouldn't be allowed to
happen. Chrome WILL NOT autofill your details or inject ANYTHING into the DOM
until you've entered/verified your CVV. Due to security with how payments work
there has to be some sort of a user interaction before any PAN is allowed to
populate the DOM. This is to avoid his exact paranoia where a CC num gets
entered automatically w/o a user's knowledge.

Since this is enforced by the browser I consider it to be pretty safe, and
appreciate the feature in my day-to-day browsing activities =)

Back to the Cleave.js lib though - that thing is going to BARF on things like
CC num autofill driven by browsers/etc. Trying to be super clever is just
going to screw-up native browser capabilities.

------
yawaramin
I wonder if it might be used for something like formatting plaintext Git
commit messages. Rules would be things like 'subject line 50 characters, then
blank line, then paragraphs or bullet points of 72 characters'. That would
solve a major issue with writing commit messages on the web.

------
calebclark
It's a good library -- I've used it multiple times.

However, I'm curious why its trending at the top of Hacker News. It's been
around since 2016.

~~~
petercooper
Might be a coincidence but we included it in this week's JavaScript Weekly on
Friday:
[https://javascriptweekly.com/issues/425](https://javascriptweekly.com/issues/425)
.. we probably saw it come up somewhere else though. One of those organic
things.

------
dmix
Strange how Visa starts with 40-49 (10x) while Mastercard is only 51-55 (4x).
I wonder if there is any logic with these prefix numbers.

~~~
jmiserez
[https://en.wikipedia.org/wiki/Payment_card_number](https://en.wikipedia.org/wiki/Payment_card_number)

> _The first (leading) digit of the IIN identifies the major industry of the
> card issuer._

4 and 5 stand for "Banking and financial".

> _The leading six digits of the card number is the issuer identification
> number (IIN), sometimes referred to as the "bank identification number
> (BIN)"._

There's a list of all 1000000 possible IINs/BINs, but it's not publicly
available:

> _The official "ISO Register of Issuer Identification Numbers", is not
> available to the general public. It is only available to institutions who
> hold IINs published in the Register, financial networks and processors.
> Institutions are required to sign a licensing agreement before they are
> given access to the Register. Several IINs are well known, especially those
> representing credit card issuers._

It's a bit like IP address blocks: there's is/was some logic to it, but to
actually know which bank a IIN/BIN belongs to (after mergers, acquisitions
etc) you have to look it up in the register.

~~~
dmix
Thanks this answers exactly what I was looking for. One of those things you
have in the back of your mind that you want to look into one day.

------
surfsvammel
I like it. Never do any front-end stuff, but if I ever do I’ll look it up.

------
folkhack
I've tried similar libraries and they all suffer the same general "I don't
know what the backspace key just did" sorta issues...

Just look at the top features listed on their Github:

* CC number - doesn't actually support all PAN formats - 19 digits exist although extraordinary rare. NEVER try to do anything fancy with your CC details field because if people try to pay you and can't you've lost a customer.

* Phone number formatting - doesn't support all phone # formats. Leave this as flat text (non-numeric) or numeric for base telephone # and a text field for extension.

* Date formatting - use type="date" so you get native mobile support for date entry.

* Numeral formatting - use type="number" so you get native mobile support for numeric entry.

~~~
root_axis
> _that one fact alone makes this trash. Like - hot garbage "screws up your
> conversion rates" trash._

That's a pretty hostile and condescending way to talk about someone else's
work. Your statement is also incorrect if applied as a general rule. I have
personally administered A/B tests for this type of masking behavior on a sales
funnel and observed an _increase_ in conversation rates (specifically for
credit card number masking) on our site.

~~~
folkhack
> Your statement is also incorrect if applied as a general rule.

I would absolutely disagree with you here. It is a generally accepted "case"
that additional validation barriers on conversion experiences cause users to
drop off. I have seen this scientifically proven by hard numbers time and time
again over my ecommerce career.

> That's a pretty hostile and condescending way to talk about someone else's
> work.

Sure, I'll take that criticism. I still think it's a horrible practice and
would professionally advise anyone against implementing this.

I do love how we like to rip on the JS community when it's convenient for us
(npm, every new framework ever, etc) but when I say a front-end lib is "hot-
garbage trash" because it breaks something as simple as backspace it's over
the line...

~~~
fnordsensei
> It is a generally accepted "case" that additional validation barriers on
> conversion experiences cause users to drop off.

Presumably the introduction of validation barriers that don't guide the input
to the intended form, then. How would the ability to type an arbitrary amount
of numbers, or letters, in a credit card number field lead to higher
conversion?

~~~
folkhack
> How would the ability to type an arbitrary amount of numbers, or letters, in
> a credit card number field lead to higher conversion?

Sure - I'll bite. But I'm also going to point out that you're swinging to the
other end of the extreme. Obviously no one in their right mind would just
allow arbitrary input...

Clearly every CC number can be represented by numbers alone (by omitting the
slashes). People are absolutely familiar with this and often will omit the
dashes in their fields all together without any filtering of characters.
Personally I key off of the "keydown" event on that field and
e.preventDefault/return false on anything non-numeric. In the future, I hope
the "inputmode" HTML attribute catches on with non-Chromium browsers - that
would eliminate my need to do this.

After the number is entered, or (personal preference) before the form is
posted, you do a simple Luhn check and show a dynamic error message RIGHT
ABOVE the field saying "hey invalid CC num yo" \- ideally you keep the
"process" button and CC num field close to each other so this happens within
the same document view without having to auto-scroll/anchor to the invalidated
field.

Then, as always - ensure you have the capability to validate that data using
the same rules on the back-end before it's allowed to be sent to your
processor, or w/e.

There ya go - there's the "everyman's" approach to CC validation on the front-
end.

------
happppy
this is super great

