Native validation as a framework. Lecture in Yandex

    Form design is one of the most critical and difficult stages of creating web interfaces. The project should receive user data, verify it and give the user feedback. Modern browsers provide the developer with a built-in API that allows phased implementation of data validation using the progressive enhancement method - from HTML / CSS to JS. Is it possible to abandon heavy libraries for validation today? What are the benefits of native validation and how thorny is the way it is used? In his report at the FrontTalks conference, LOVATA technical director Pavel Lovtsevich reviewed the main aspects of working with the HTML5 Constraint Validation API.


    - Hello everyone, my name is Pavel, I came from Minsk. I’ll talk about the validation of web forms based on native, built-in browser technologies.

    I work as a technical director at LOVATA, and I also work as technical director at our 2doc.by product startup, this is a medical search with a B2B part, which consists in automating the work of medical centers.

    I have been conducting events in Minsk for almost 10 years. For a long time it was only Web Standard Days, but over the last year Ostap suffered, and immediately plus three events. You can hang medals like Brezhnev. Come to Minsk, we have a lot of cool events, we will be friends with cities and communities.

    I am sure that there will not be a person in the hall who would not at least once do a web form in some form, at least one text field for receiving data. This is one of the most important things in the interface of websites and applications, because it directly affects the conversion, the success of the project.

    There is such a Beimard Research Institute, which is engaged in usability research. They conducted research on 37 open sources, which, in turn, conducted independent research from 2012 to 2017 in the field of using web forms and came to the following conclusions: almost 70% of users throw their baskets. Of these, 60% abandon them for the reason that at some point they were not ready to start making a purchase, but simply got acquainted with the goods. At the same time, 27% of users clearly indicated that they quit placing an order due to the fact that the web form was too complicated. They encountered certain problems when working with her. Or she was too long. The average number of fields on the checkout form in this study was about 15. Either there were problems with validation. Anyway,

    Based on this study, it was concluded that front-end improvements to web forms can lead to a 35 percent improvement in conversion rates. Considering the size of the market in the USA in e-commerce, this is $ 260 billion, we will only make the web form better, reduce the number of fields from 15 to 7–8, and make a good relevant validation. And the industry will gain an additional 260 billion per year.

    Validation is one of the most important steps in working with user web forms. Previously, we had non-native methods, there were a lot of them, everyone wrote his own library. Npm libraries for jQuery are currently very popular. To just validate form fields, you drag a jQuery bundle that weighs 80 KB.

    Everything can be simplified by using the tools built into the browser.



    Validation is such a serious thing that even there is a special ISO standard that denotes the definition of validation.

    What is the purpose of validation? Firstly, obtaining the correct data in the correct format for subsequent processing. Secondly, protecting the user from all kinds of data interception. And finally, application protection. We do not want to be hacked through a web form and gain access to the user data that he entered earlier.

    What is the most important field of client validation without which nowhere? Server Validation! This is the main method of validation, it is responsible for security. Client validation is primarily what affects the user experience, the same UX. Good validation helps in increasing conversion.

    What does good validation consist of? A study was conducted, Martin Trader based on several sources, including a large study of Luc Wrublewski, a well-known specialist in the field of usability. He came to the following conclusions that, firstly, validation should be in the right place. This refers to the form of a message about a certain error, where we display a user error message so that it is convenient for him to work with it.

    Secondly, at the right time - inline validation, no one wants to fill out the entire form, and at the end, when submitting, see that we have some errors, come back and start again. Even worse if we lose some data.

    Third, a suitable color. We are used to seeing that in the forms the error fields are somehow highlighted in red, however, studies show that one of the best options is still orange. It does not put so much pressure on the user, plus it is the color that color blind people can see.

    Fourth, understandable language. This is a broad concept. We must explicitly inform the user that he did wrong and how to fix it, and not just highlight the erroneously filled field, and leave the user to deal with him one on one.



    A study by Luc Wrublewski suggests that inline validation leads to an increase in the following indicators. The success of completing the form is increased by 22%; the number of errors when filling it is reduced by 22%; user satisfaction is growing by 31%; time for filling out a web form, all other things being equal, is reduced by 42%; and users’ eyes are straining less during inline validation, since they don’t have to constantly run across different fields, so the number of eye fixations on the web form is reduced by 47%.

    The main topic of my report is a special API that has been built into the browser for a long time, but so far this topic has not been actively promoted.

    This year I took up this topic, there were also several studies, for example, Peter Paul Koch from the Netherlands conducted a large study on the use of native validation in the browser, and Chris Ferdinandi also wrote a large series of articles.

    What can we do with native validation?



    In terms of support, everything is pretty good. In this case, we mean basic support, which means that we can indicate the fields as mandatory and catch their status of validity or invalidity, whether the field is filled or not.

    In this situation, if the browser supports Form validation, we say that it supports some native JS API methods.

    The first way to enable validation is to simply mark the field using the Required attribute as required.



    On the left, the field is marked with the required attribute; on the right, it is not. Right and form pseudo-classes are hung right on the form and on the elements of this form, which highlight their state. As you can see, the form itself can also catch the state of validity or invalidity by “listening” to the state of the fields inside. The inner frame can also catch these conditions.

    If we try to enter something here, we will see that the form and fieldset have received a valid state of validity, and the form can be submitted.



    In terms of support, we have problems only with Edge and IE. They consist in the fact that in these browsers, fieldset and form do not support the validity / invalidity state. But I do not see this as a big problem, because I have not met cases in my practice when it would be very important for us to catch this state precisely on these elements.

    In the above form, the button was initially highlighted in green, as In browsers, this form element is always in a state of validity, and only in Firefox there is a special vendor pseudo-class and only for a button when it is input in type submit. A separate narrow story, I doubt that you may need it.





    The second way to enable validation using an attribute. We can set the length of the string in the field, limit it to the maximum and minimum value, specify the pattern, etc.

    Required supports all kinds of form fields.

    With the string length (minlength / maxlength), it is important to understand that in addition to field types such as file, checkbox, radio, Boolean types, there are field types that do not support this type of restriction. These are numerical fields, for example, either type number or type data and all its variations, because they have their own special delimiters that evaluate not the length of the string, but the value of the value entered in the field.

    For fields whose values ​​can be estimated in value, the min and max attributes are used as a constraint.

    Step is also used with this kind of field. Its main task is to set the step of the value that we can enter in the field. This can be a multiplicity of a certain number, a time interval, etc.

    Pattern applies to all text fields except numeric and date fields. This is the most well-supported attribute element in forms, with the help of which we can write fallbacks for browsers that for one reason or another do not understand the purpose of a certain type of field, which we will consider later.



    The third type of inclusion of validation is the indication of a specific type of field, its semantics. In addition to the standard ones - text, password, file, text area - you can drop select here, there are also number, range, email, tel, url and date. C date is still not very good in terms of support, but through two versions of Firefox we will have almost the best date picker, all that’s left for Safari to do is pull up.

    Let's try to create a form using the progressive improvement method. We are all going to a situation where for the past 10 years we have been collecting everything in bundles, all our scripts, styles, and as HTTP 2 spreads, which is sharpened by multi-threaded loading of our assets to pages, we will gradually refuse to glue files. We will most likely have situations when some of the resources may be underloaded. Yes, we can catch similar states using various JS APIs, react to them one way or another, but at the same time, if we do form validation using CSS, we can improve the user experience by the time JS works.



    Imagine that this is some kind of abstract order form. Everything is highlighted in green, no restrictions are set. If we set the required field constraint, we will immediately see which fields become highlighted in red. We’ll enter something in the required field, the field is filled in, everything has become okay.



    ( Work with the form in the video starting at 13:30- approx. ed.) Type number support is good enough, only in Edge there is a problem in that it does not display special arrow controls in the field that allow the user not to enter data, but switch them using these arrows. There is a feature in Firefox that it allows you to enter a non-numeric value in this type of field, and Chromium browsers and Edge, in principle, will not allow this. This is more correct behavior, since it helps prevent the creation of a situation when an error occurs. Using this field we will limit the corresponding order field in our form.



    What is wrong in the form that I found at Sheremetyevo Airport? The wrong field type is used here, but why? Used type number, designed for fields that take on the values ​​of the form of a floating point number. If this is just a set of numbers, as in this case, it is just a code in SMS, then this is not the situation when you need a type number. In this situation, you should use a regular type text with a pattern that limits the range of characters that you can drive here.

    Exactly the same situation in the form of password recovery in Instagram. This is a typical incorrect use case of type number for fields. Do not do it, it is wrong.



    There are three more special semantic field types. The first is e-mail. Its main value is to validate e-mail. It has a rather soft validation according to RFC 822, which allows the presence of e-mail on localhost, so by default this field will be validated if you simply enter a certain value before the dog symbol and after without specifying a top-level domain.

    Also the purpose of this field is to enable special keys on the virtual keyboard of your devices, when clicking on the keyboard will display a dog icon on your keyboard.

    The tel type does not have any special pattern restrictions, the phone number formats are too different worldwide. Its main task is to enable the numeric keypad on the device, because when typing phones in most cases you do not need letters.

    The type of URL works in a similar way as email, there is enough light validation, which allows you to actually specify localhost without specifying a domain. These requirements can be tightened using the pattern attribute.



    Let's try to tighten restrictions in our form. In addition to the fact that we set the type number, we hypothetically imagine that the user can place an order of at least two units of goods and no more than 20.



    We have address and city fields. We believe that a city of less than two letters cannot exist in principle, and we need to deliver. We limit this field to two characters, and assume that there is hardly a city with a name of more than 100 characters. But with restrictions on the maximum line length, always be careful. When validating the same e-mail and so on, you can never be sure to the end what real value can be maximized. In any case, in fields, even from a security point of view, it is worth limiting the length of the field, but make it comfortable enough to avoid a situation where you do not get into the real data that can be entered there.



    Support for the pattern attribute is pretty good, no problems anywhere. Safari on iOS version 10.2 had a problem with the fact that when the pattern was set for the field, the form was submitted, despite the fact that the data invalid event was triggered.



    The main possibilities of using pattern are the ability to specify ranges of values, indicate only characters of numbers or letters, variable values ​​and specify the range of minimum and maximum line lengths.



    Let's try to validate the pattern. I am from Minsk, we have all zip codes starting at 220, only the last three numbers change.



    You see regular Perl-like regulars that we are used to in JS. It is worth noting that the usual characters of the beginning and end of the line, if used with the Constraint Validation API, can be omitted. A shorter record without them will work the same.



    I specified the title attribute, the standard attribute of the tooltip that pops up when you hover over an element. In combination with a text field that has a pattern set, this title attribute will pop up in the native tooltip, informing the user that he entered incorrect data. This is the only way for a single field type to set the contents of this message without JS.

    What are the obvious bugs at this stage and how can we solve them?



    ( Work with the form in the video starting at 19:40- approx. Ed.) The left field is required, it has a maximum string limit of four characters. You see six characters. This is a rather unpleasant moment, implemented equally in all browsers, which consists in the fact that if we have a default value of our field that exceeds our limit, then the invalid flag will not be lit.

    If we try to change it, the cursor does not start, because the maxlength attribute does not allow you to enter more than the allowable number of characters, this works the same in all browsers.

    But as soon as I try to delete one element, this event immediately fires. Case, when you give the user a field that is already filled with previously invalid data, it’s quite atypical, but be aware of this feature.

    For minimum values ​​the same. Here a minimum of 4 is set, 2 is entered - valid. We begin to enter - it is invalid. Reached 4 - valid.



    There is a problem in Edge that minlength is not supported as an attribute. But you can get around this by simply using a pattern that will work in conjunction with your minlength and maxlength attributes, and it will take precedence.



    Type number. If the browser does not understand some special type of field, then the default behavior is that it will fall for a regular type text. If you have a case when some very old browser does not support type number, but you need to do this, you can set a regularity that will allow you to validate only the numbers allowed in this type of field.



    If we want to set a limit on the value, the regular can’t calculate the value of the value, but we can use these techniques to specify ranges of acceptable values. Naturally, this is not very convenient, and the larger the allowable value, the greater the regularity. Therefore, this is a working case, but very special, because it can be difficult and inconvenient to work with it. But it works.



    Type of email. Default RFC 822, which allows the presence of e-mail on localhost. Naturally, this does not suit us, we want to get a real user e-mail, so we can improve the validation of an existing semantic field by adding the correct pattern.



    I didn’t drive the real pattern, it would be too big, you can google the real pattern for RFC 822. The pattern for the usual kind of e-mail is also easily google.



    Another fairly important type of field is date. Firefox will soon come to support this type. This is not in our form, but I will show a way in which it is also possible to make validation without JS of this type of field.



    For example, if we want to receive data from the user about the date in the format YYYY-MM-DD, then the regularity in the pattern attribute will help in this matter.



    ( Work with the form in the video starting at 11:25 p.m. - Ed.) Let's try to fill out our form. The language in which the standard message about filling is displayed is not the default OS locale, it is the browser locale. If you need to manage the language, number formats, money, dates, etc., you can use the JS API - Internationalization specifically to configure these things. At this stage, we only work with the CSS part of validation.

    The minimum numerical value is set for the field 2. Enter 1 - not suitable. We look at what the browser says - indicates “minimum 2”, 12 falls into the range, so everything is OK.

    I made one field optional to see how the field might look like other fields. We believe that the username is not important for us in this situation.

    We are trying to drive an e-mail. The same title surfaced that I entered in the corresponding attribute of this field, which says that we want to validate the full e-mail, and not RFC 822.

    Index. The pattern is also set, the title pops up.

    City and address - at least two characters, okay.

    What should confuse you in this form? Fields are red. The form initially strikes users that the data is invalid. The study that I referred to says that inline validation should only happen when the user has explicitly entered data, and when he left this field, only then can we offer data validation.

    There is a special pseudo-class: user-error in the living standard from WHATWG, it is not supported in browsers, unfortunately. This is a special pseudo-class designed to validate fields into which the user has explicitly entered data.

    There is another pseudo-class: user-invalid from the developers of the W3C specification, it is also not supported in browsers.

    Do not despair, there is another pseudo-class: placeholder-shown. This is a special pseudo-class that catches the state of the display of a placeholder in the form field. How can we use it to solve the problem that I mentioned earlier?



    Firstly, there may already be some placeholders in the form fields that would help the user understand in what format to enter this data. If the user entered some data in the field, the placeholder disappeared, and we can catch this state and rely on it to validate the form.

    If you do not have an explicit placeholder, then you can create an empty placeholder just with a space, and this will work just the same.



    We catch the state that the placeholder is not displayed, that the field is out of focus, that is, the user has finished entering data.



    Well, that there is a state of invalidity. We can light a flag, explicitly mark the field as invalid.



    With support, everything would be nice if it weren't for Edge, but it has such a low share even in the global context that, based on the fact that this type of validation is only the initial stage, until JS arrives, I think it's not so scary and critical.

    ( Work with the form in the video starting at 27:25 - approx. Ed.) Here is the same form, but with this long selector. We enter something - it does not fit. We drive in the correct data, we leave the field - it fits. And also further, until we introduce something correct, the field will in no way annoy us and somehow display incorrectly.

    The problems of native messages are quite serious.

    The first problem is the impossibility of styling. In principle, in no way can you customize the native browser message for your design.

    Different principles of work in different browsers. They relate to areas such as the time of occurrence, the duration of the appearance of a native message, the conditions of occurrence, and so on.

    The saddest thing is that in Chromium browsers, the text that appears in error messages is, in principle, not read by the screen reader.

    Let's try to improve our forms using JS.



    The Constraint Validation API contains several methods for working with your forms at once. Firstly, this is the checkValidity method, which returns true / false, lighting the field invalidation or validity event.

    The second reportValidity method does the same, plus it displays a native message. setCustomValidity returns the value of the field and allows us to specify a custom message in this field.

    The willValidate property, in fact, fires on submit and indicates which field is valid or not, because we can exclude individual fields from validation by specifying the novalidate attribute for a specific field.

    The Valiidity property allows you to return an object with various restrictions that we can catch in order to explicitly tell the user what he was wrong about.

    You must immediately say that reportValidity () is a dangerous property, never use it.



    ( Work with the form in the video starting at 29:30- approx. Ed.) We’ll check the invalid field in the Chrome browser. I translate the input focus into it and cannot get out of here. Whatever you try to do, if you end up in Chrome in an invalid field that is validated by this method, until you make the data in this field valid, you cannot exit this field. Just do not use this method.

    The second method is a bit crooked, but it can be used.



    We can check the specific property of what exactly went wrong with the user data and display the necessary message.



    When we setCustomValidity and pass the string, the invalid event is triggered and the field lights up as invalid.



    If we pass an empty string, such a feature of the implementation of this API, then the message will not be displayed in the field, but the field will become valid.



    The Validity object contains a whole bunch of ways to check everything that we can check, the length of the string, all those features based on the type of field, field attributes, everything is checked using these properties.



    You can build completely different own checks, not relying only on what the authors of the specification offer you.



    A way to make a field invalid by simply checking the two password fields for compliance. You can think of many such cases; this will be an extension of the native API.



    We follow the principle of progressive improvement. What do we want to get? State the fields, turn off the native validation, check the validity when focus is removed, identify the error, show the error message, style this message, make the message friendly for screen readers and check the fields by form submit.



    We get the state of the fields by checking the Validity property.



    For example, we want to explicitly indicate the forms whose validation management we want to intercept in order to better validate them. We simply catch all forms with an explicitly specified Validate class and set the novalidate control attribute in them, which disables the impossibility of submitting the form, while the rest of the validation works, all validity and invalidity events are saved.



    Next, we hang up the event handler and listen to all blur events for focus removal, this is the best way to check the data when focus is taken.



    We will create a special hasError function that will run through all these properties to determine whether the field is valid or not, across all Validity properties.





    We look, if we have a certain field invalid, and invalid returns from the form, then we will run on all the other properties to check each of them for compliance with the restriction.



    We can extend the type mismatch check. Type mismatch corresponds to both e-mail and URL, but to highlight a specific e-mail, we can indicate that the problem is with it.



    We can also help the user by reading the attributes minLength, maxLength, with the minimum and maximum values ​​of the value, in order to explicitly indicate what is wrong and what we expect from the user. The same goes for a number field.



    If there is a pattern, we will take the title value from the pattern to display it in our custom message.



    We take and withdraw.





    Next we want to display the error.



    We will also have a separate function for this, we will hang an error message in our handler.



    We will add the error class for our fields.



    We will also pick up the id of this field, then to interact with it and with the error message block.



    How will we display an error message? We will just create a div element with the desired class, bind it to the desired field. And continue to display.







    Next, we will associate our field with this div using a special aria-attribute, so that screen readers understand that this error belongs to this field, and id helps us with this.



    Hide the error message is also quite simple.



    We create a special function, hang it in the handler.



    Our task will be to remove the error class from the field, to remove the aria-attribute.



    Look id again and then hide this error.





    We should not forget that besides the fact that validation can occur inline, it is also necessary to handle the situation when we validate submit forms.



    We create the corresponding event listener, check in the same way, run through all the fields.





    In the event of errors, we intercept the default behavior of the button with preventDefault and display an error message.





    What is important, having previously received the id of all the fields, we translate the input focus to the first of the fields, which is invalid. At the same time, we will not have a situation that was in Chrome when the field is invalid, but you cannot exit it.



    We got the form. (Work with the form in the video starting at 35:40 - approx. Ed.) Fields popped up, fill them, everything is OK, the form has been sent.

    There is an excellent series of articles from Chris Ferdinandi , I mentioned it earlier. Chris wrote the Validate JS script, parts of this script I demonstrated today. The script runs on top of the native API and allows you to create a form, which, in turn, works by the method of progressive improvement. The script is very simple, all you need is to connect it to the page, add the Validate class for the necessary forms and enjoy. This script is in the second part of the articles.

    In the third part of the articles, he talks about Polyfill, which Chris wrote and which extends support even to the IE9 browser to use native validation.

    Great series of articles by Peter-Paul Kochin May 2017, she appeared on the Samsung Internet developers blog. This is a titanic study in which you can learn about all the features of the implementation of this API in browsers, about all the jambs. Knowing about them, you can decide whether to use this API in your project.

    Using the native API clearly allows us to progressively improve our form. Before JS arrives to us, we can already process user data.

    The script that I used in the presentation weighs only 6 KB, in a minified form 2.7 KB. Compare: the most popular jQuery validation pulls only 80k in jQuery.

    Using this API allows you to understand their features, give feedback to the authors of the specification about what is convenient and what is not. At one time, jQuery also appeared as an API on top of the API, and the best things from jQuery went into the ECMAScript specification. I am convinced: the more developers will access this API and use it in their work, the more feedback will be and the sooner the API will be brought to normal.



    When the API is brought to such a state that some layers are not needed, the native validation will work much faster than any script in the script that you include in the script from the outside. Andrei Sitnik also says that on top of any API you can write a more convenient API and use it safely. That's all, thanks.

    Also popular now: