JSFiddle - React, Tailwind, and code Playground

by danya_postfactum

HTML

<!-- <script src="addEventListener.js"></script>
<script src="classList.js"></script> -->
<form action="">
    <p><input type="text" name="name" required="" pattern="[a-zA-Z]{2,64}" title="От 2 до 64 символов латинского алфавита." placeholder="Имя" /></p>
    <p><input type="email" name="email" required="" pattern="[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+" placeholder="Email" /></p>
    <p><input type="password" name="password" required="" pattern=".{2,64}" placeholder="Пароль" /></p>
    <p><input type="password" name="passwordConfirm" required="" placeholder="Пароль еще раз" /></p>
    <p><button type="submit">Отправить</button></p>
</form>
<script>
    var form = document.querySelector('form');
    var validator = new FormValidator(form, {
       'passwordConfirm': function(input) {
           return {state: input.value == input.form.password.value, error: 'Пароли не совпадают.'}
       }
    });
</script>

CSS

input{
        border: 1px solid #777;
    }
    input:focus{
        outline: none;
        box-shadow: 0 0 5px rgb(179, 179, 179);
    }
    .state-error{
        border-color: red;
    }
    .state-success{
        border-color: green;
    }

    .validation-message {
        padding: 15px;
        background: #fff;
        border-radius: 4px;
        border: 1px solid #C5C5C5;
        box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
        position: fixed;
        margin-top: 10px;
        font: 11px/1.4 Verdana;
        cursor: default;
        white-space: pre-wrap;
        max-width: 26em;
    }
    .validation-message:after, .validation-message:before {
        bottom: 100%;
        left: 1.2em;
        border: solid transparent;
        content: " ";
        height: 0;
        width: 0;
        position: absolute;
        pointer-events: none;
    }
    .validation-message:before {
        border-color: rgba(197, 197, 197, 0);
        border-bottom-color: #C5C5C5;
        border-width: 10px;
        margin-left: -10px;
    }
    .validation-message:after {
        border-color: rgba(255, 255, 255, 0);
        border-bottom-color: #fff;
        border-width: 9px;
        margin-left: -9px;
    }

JavaScript

function FormValidator(form, rules) {
        form.noValidate = true;
        var events = ['submit', 'input'];
        if (!('oninput' in form))
            events = ['submit', 'keydown', 'paste', 'cut', 'drop', 'dragend'];
        for (var i = 0; i < events.length; i++)
            form.addEventListener(events[i], this);
        this.form = form;
        this.rules = rules;
        this.message = null;
        this.activeElement = null;
    }
    FormValidator.prototype = {
        constructor: FormValidator,
        handleEvent: function(event) {
            switch (event.type) {
                case 'input':
                    var validity = this.validateInput(event.target)
                    if (this.activeElement === event.target) {
                        if (validity.state)
                            this.hideMessage()
                        else
                            this.updateMessage(validity.error);
                    }
                    break;
                case 'submit':
                    if (!this.validateInputs(this.getInputs()))
                        event.preventDefault();
                    break;
                case 'blur':
                    this.hideMessage(event.target);
                default:
                    var target = event.target;
                    var self = this;
                    setTimeout(function(){
                        self.validateInput(target);
                    }, 0);
            }
        },
        createMessage: function() {
            this.message = document.createElement('div');
            this.message.className = 'validation-message';
            this.message.addEventListener('mousedown', function(e) {
                e.preventDefault();
            });
        },
        showMessage: function(element, text) {
            this.activeElement = element;
            element.focus();
            if (!this.message)
                this.createMessage();
            var rect =...