<form id="form" method="post" action="/send.php" class="form">
                <h2>Регистрация</h2>
                <label class="form-control">
                    <span>Имя</span>
                    <input 
                    data-req="Имя обязательное" 
                    data-name="Проверьте правильность Имени"
                    data-success="Поля валидное"
                    type="text" 
                    name="username" 
                    placeholder="Введите здесь Ваше имя"/>
                </label>
                <label class="form-control">
                    <span>Фамилия</span>
                    <input 
                    data-req="Фамилия обязательное" 
                    data-surname="Проверьте правильность Фамилии"
                    data-success="Поля валидное"
                    type="text" 
                    name="userlastname" 
                    placeholder="Введите здесь Вашу фамилию"/>
                </label>
                <label class="form-control">
                    <span>Почта</span>
                    <input
                            data-req="Email обязателен"
                            data-email="Проверьте правильность email"
                            data-success="Поля валидное"
                            type="text" name="email"
                            placeholder="Введите Вашу почту"
                    />
                </label>
                <label class="form-control">
                    <span>Номер телефона</span>
                    <input
                            data-req="Номер телефона обязателен"
                            data-tel="Проверьте правильность номера телефона"
                            data-success="Поля валидное"
                            type="tel" name="tel"
                            placeholder="Введите Ваш номер телефона"
                    />
                </label>
                <label class="form-control">
                    <span>Пароль</span>
                    <input
                            data-req="Пароль обязателен"
                            data-password="Проверьте правильность пароля"
                            data-success="Поля валидное"
                            type="password" name="password"
                            placeholder="Введите Ваш пароль"
                    />
                </label>
                <label class="form-control">
                    <span>Подтверждение пароля</span>
                    <input
                            data-req="Пароль обязателен"
                            data-password="Проверьте правильность пароля"
                            data-success="Поля валидное"
                            type="password" name="password2"
                            placeholder="Введите пароль снова"
                    />
                </label>
                <label class="form-control form-control--line">
                    <span>Я согласен с условиями</span>
                    <input name="agree" data-req="Обязательно согласитесь" type="checkbox"/>
                </label>
                <button type="submit">Зарегистрироваться</button>
            </form>
@import url('https://fonts.googleapis.com/css?family=Nunito&display=swap');

:root {
    --success-color: #0cb854;
    --error-color: #ee1f09;
}

* {
    box-sizing: border-box;
}

body {
    background-color: #f9fafb;
    font-family: 'Nunito', sans-serif;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    margin: 0;
}

.container {
    background-color: #fff;
    border-radius: 5px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
    width: 500px;
}

h2 {
    text-align: center;
    margin: 0 0 20px;
}

.form {
    padding: 30px 40px;
}

.form-control {
    display: block;
    margin-bottom: 10px;
    padding-bottom: 20px;
    position: relative;
}

.form-control span {
    color: rgb(58, 58, 58);
    display: block;
    margin-bottom: 5px;
}

.form-control input {
    border: 2px solid #c9c9c9;
    border-radius: 4px;
    display: block;
    width: 100%;
    padding: 10px;
    font-size: 14px;
}

.form-control input:focus {
    outline: 0;
    border-color: #777;
}

.form-control--line {
    display: flex;
    align-items: center;
}
.form-control--line span {
    margin-bottom: 0;
    margin-right: 5px;
}
.form-control--line input {
    width: auto;
}

.form-control.success input {
    border-color: var(--success-color);
}

.form-control.error input {
    border-color: var(--error-color);
}

.form-control small.error-item {
    color: var(--error-color);
    visibility: hidden;
}

.form-control small.success-item {
    color: var(--success-color);
    visibility: hidden;
}

.form-control.error small,
.form-control.success small {
    display: block;
    visibility: visible;
}

.form button {
    cursor: pointer;
    background-color: #3498db;
    border: 2px solid #3498db;
    border-radius: 4px;
    color: #fff;
    display: block;
    font-size: 16px;
    padding: 10px;
    margin-top: 20px;
    width: 100%;
}
function ValidateForm (_form) {
    const errorClass = 'error';
    const successClass = 'success';
    const labelClass = 'form-control';
    const errorItemClass = 'error-item';
    const successItemClass = 'success-item'
    const _elements = _form.elements;

    _form.addEventListener('submit', event => {
        event.preventDefault();
        const formData = new FormData(_form);
        this.checkFormElements();

        if (this.formValidate()) {
            try {
                fetch(_form.action, {
                    method: _form.method,
                    body: formData
                })
                .then(response => {
                    if (response.ok) {
                        console.log('Форма отправлена успешно');
                    } else {
                        console.log('Ошибка отправки формы');
                    }
                })
            } catch(error) {
                console.error('Ошибка: ', error);
            }
        }
    });

    for(let _element of _elements) {
        _element.addEventListener('input', () => {
            this.checkFormSingleElement(_element);
        });
    }
    
    this.checkFormElements = function () {
        for(let _element of _elements) {
            this.checkFormSingleElement(_element);
        }
    }

    this.checkFormSingleElement = function (_element) {
        const reqMessage = _element.dataset.req;
        const emailMessage = _element.dataset.email;
        const telMessage = _element.dataset.tel;
        const nameMessage = _element.dataset.name;
        const surNameMessage = _element.dataset.surname;
        const passwordMessage = _element.dataset.password;
        const successMessage = _element.dataset.success;
        

        this.clearErrorAndSuccess(_element);

        if (reqMessage) {
            this.checkRequired(_element, reqMessage);
        }
        if (emailMessage) {
            this.checkEmail(_element, emailMessage, successMessage);
        }
        if (telMessage) {
            this.checkTel(_element, telMessage, successMessage);
        }
        if (nameMessage) {
            this.checkName(_element, nameMessage, successMessage);
        }
        if (surNameMessage) {
            this.checkName(_element, surNameMessage, successMessage);
        }
        if(passwordMessage) {
            this.checkPassword(passwordMessage, successMessage);
        }
    }

    this.checkRequired = function (_element, reqMessage) {
        const notValidStr = _element.value.trim().length === 0;
        const notValidCheckbox = _element.type === 'checkbox' && _element.checked === false;
        if (notValidStr || notValidCheckbox) {
            this.createErrorTemplate(_element, reqMessage);
        } 
    }

    this.checkName = function (_element, message, successMessage) {
        const nameStr = _element.value.trim();
        const nameRegExp = /^[a-zA-Zа-яА-ЯёЁ\s-]{2,50}$/;
        if (!nameRegExp.test(nameStr)) {
            this.createErrorTemplate(_element, message);
        } else {
            this.createSuccessTemplate(_element, successMessage);
        }
    }

    this.checkEmail = function (_element, message, successMessage) {
        const emailStr = _element.value.trim();
        const emailRegExp = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
        if (!emailRegExp.test(emailStr)) {
            this.createErrorTemplate(_element, message);
        } else {
            this.createSuccessTemplate(_element, successMessage);
        }
    }

    this.checkTel = function (_element, message, successMessage) {
        const phoneStr = _element.value.trim();
        const phoneRegExp = /^\+?[0-9\s\-()]{7,}$/;
        if (!phoneRegExp.test(phoneStr)) {
            this.createErrorTemplate(_element, message);
        } else {
            this.createSuccessTemplate(_element, successMessage);
        }
    }

    this.checkPassword = function (message, successMessage) {
        const allPasswords = _form.querySelectorAll('input[type="password"]');
        const arrPasswordValues = Array.from(allPasswords).map(item => item.value.trim());

        const passwordRegExp = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;

        const checkPassByRegExp = arrPasswordValues.every(pass => passwordRegExp.test(pass));
        const checkPassByUniqueness = new Set(arrPasswordValues).size === 1;

        if (!checkPassByUniqueness || !checkPassByRegExp) {
            allPasswords.forEach((value) => this.createErrorTemplate(value, message));
        } else {
            allPasswords.forEach(value => this.createSuccessTemplate(value, successMessage));
        }
    }

    this.createErrorTemplate = function (_element, message) {
        const parent = _element.closest(`.${labelClass}`);
        parent.classList.add(errorClass);
        parent.insertAdjacentHTML('beforeend', `<small class=${errorItemClass}>${message}</small>`);
    }

    this.createSuccessTemplate = function (_element, message) {
        const parent = _element.closest(`.${labelClass}`);
        if (parent) {
            parent.classList.add(successClass);
            parent.insertAdjacentHTML('beforeend',`<small class=${successItemClass}>${message}</small>`)
        }
    }

    this.clearErrorAndSuccess = function (_element) {
        const parent = _element.closest(`.${labelClass}`);
        if (parent) {
            parent.classList.remove(errorClass, successClass);
            parent.querySelectorAll(`.${errorItemClass}, .${successItemClass}`).forEach(item => item.remove());
        }
    }

    this.formValidate = function () {
        let allValid = true;
        for(let _element of _elements) {
            const parent = _element.closest(`.${labelClass}`);
            if (parent.classList.contains(errorClass)) {
                allValid = false;
                break;
            }
        }
        return allValid;
    }

}
new ValidateForm(document.querySelector('#form'));

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.