JSFiddle - React, Tailwind, and code Playground
by LyndseyB
HTML
<div class='o-wrapper'>
<form method="post" class='c-signup-form' data-js='formValidate'>
<label class='c-signup-form__label'><span>First Name </span><input type="text" name="firstName" data-required></label>
<label class='c-signup-form__label'><span>Last Name </span><input type="text" name="lastName" data-required></label>
<label class='c-signup-form__label'><span>Email Address </span><input type="text" name="emailAddress" data-required></label>
<label><button type="submit">Submit Form</button></label>
</form>
</div>
SCSS
* {
box-sizing: border-box;
}
.o-wrapper {
margin-left: auto;
margin-right: auto;
max-width: 1000px;
}
.c-signup-form {
border: 1px solid #e3e2de;
border-radius: 5px;
padding: 1rem;
background-color: #f7f7f7;
}
.c-signup-form__label {
display: block;
padding-bottom: 1rem;
}
.c-signup-form__label > span {
display: inline-block;
width: 25%;
}
.c-signup-form__label > input {
padding-top: 3px;
padding-bottom: 3px;
border: 1px solid #aaa;
}
.c-alert {
display: block;
padding: 1rem;
width: 100%;
margin-bottom: 1rem;
}
.c-alert--warn {
border-color: #c28a8a;
background-color: #ffe0e0;
}
.c-alert--ok {
border-color: #17a55b;
background-color: #c6e3c7;
}
.u-required-field {
color: #c28a8a;
font-weight: bold;
float: right;
padding-right: 5px;
}
.u-field-invalid {
background-color: #ffe0e0;
border: 1px solid #c28a8a;
}
.u-hidden {
visibility: hidden;
}
@media (max-width: 500px) {
.c-signup-form__label > span {
display: block;
width: 100%;
padding-bottom: 0.5rem;
}
.c-signup-form__label > span ~ * {
width: 60%;
}
}
JavaScript
(function() {
var utils = {
getRequiredField: function() {
return '<span class="u-required-field">*</span>';
},
checkEmpty(fields) {
return [].filter.call(fields, function(field) {
return !field || field.value === '';
});
},
createAlert(element, message, type = 'warn') {
var alert = '<span class="c-alert c-alert--'+ type + '">' + message + '</span>';
if(element.querySelector('.c-alert')) {
element.querySelector('.c-alert').classList.add('c-alert--'+ type);
element.querySelector('.c-alert').innerHTML = message;
return;
}
element.insertAdjacentHTML('afterbegin', alert);
}
};
var page = {
init: function() {
var methods = document.querySelectorAll('[data-js]');
[].forEach.call(methods, function(method) {
var methodName = method.getAttribute('data-js');
if(page[methodName]) {
page[methodName](method);
}
});
}
};
page.formValidate = function(element) {
if(!element) {
return;
}
var fields = element.querySelectorAll('[data-required]');
if(fields.length > 0) {
[].forEach.call(fields, function(field) {
field.previousSibling.innerHTML += utils.getRequiredField();
field.addEventListener('input', function() {
if(this.value !== '') {
this.classList.remove('u-field-invalid');
}
});
});
}
element.querySelector('[type="submit"]').addEventListener('click', function(e) {
e.preventDefault();
var invalidFields = utils.checkEmpty(fields);
var button = this;
if(invalidFields.length > 0) {
[].forEach.call(invalidFields, function(invalidField) {
invalidField.classList.add('u-field-invalid');
});
utils.createAlert(element, 'Please fill out all required fields');
} else {
// create AJAX request
...