header.c-banner
div.c-container
.c-contact
h1 We'd love to hear from you.
p Have a question about us? Need to talk to customer service? Have a great idea? Drop us a line and we'll get back to you as soon as we can.
p Have an urgent problem about an order? Call our warehouse at 1234-1234.
p We can also get in touch on
a(href="https://www.twitter.com/" target="_blank") Twitter
| .
form.c-form#form
label(for="email")
span.c-form-label Email
abbr(title="Required") *
input.c-form-input#form-email(type="email", name="email" required='required' pattern=".{3,}")
span.u-alert#form-email-error Please enter a valid email format
label(for="name")
span.c-form-label Name
input.c-form-input#form-name(type="text", name="name" pattern="^[A-Za-z ,.'-]+$")
span.u-alert#form-name-error Please enter a valid name with alphabets only
label(for="message")
span.c-form-label Message
abbr(title="Required") *
textarea.c-form-input#form-message(minlength="10", maxlength="200",rows="4", name="message", required='required')
span.c-form-input__length
span#form-message-length 0
| /200
span.u-alert#form-message-error Please enter at least 10 characters and less than 200 characters.
label(for="signup").c-form-group
input.c-form-checkbox#form-signup(type="checkbox", name="signup")
span.c-form-label Sign me up for latest updates
input.c-form-submit#form-submit(type="submit", value="Submit", name="submit")
span.u-alert#form-submit-error Please correct all information and try again.
div.c-thankyou.u-hide#form-thankyou
h1 Thank you!
p We will contact you as soon as possible.
footer
p Page design from
a(href="https://uigarage.net/boka-contact-form/" target="_blank") Boka Contact Form
View Compiled
//text color
$text: #7E7E7E
$alert: #EF5350
$btn: #FB9375
$btn-hover: #FB9375
$theme: #FF9473
//mobile query based on bootstrap
$phone: "only screen and (min-width : 576px)"
$tablet: "only screen and (min-width : 768px)"
$laptop: "only screen and (min-width : 992px)"
$desktop: "only screen and (min-width : 1200px)"
body
font-family: 'Lato', sans-serif
margin: 0
padding: 0
width: 100%
height: 100%
line-height: 1.48
color: $text
*
box-sizing: border-box
h1,h2,h3
font-family: 'Roboto', sans-serif
color: $text
h1
font-size: 1.8em
margin-bottom: 0.8em
a,
a:visited,
a:focus,
a:active
color: $text
.c-banner
position: relative
height: 18em
background-image: url('//snowleo208.github.io/100-Days-of-Code/instant-form-validation/giulia-bertelli-116358-unsplash.jpg')
background-size: cover
background-repeat: no-repeat
background-position: 50% 60%
border-bottom: solid 5px $theme
@media #{$laptop}
height: 20em
&:before
content: ''
position: absolute
bottom: -1.2em
left: calc((100% - 2.4em) / 2)
width: 0
height: 0
border-style: solid
border-width: 1.2em 1.2em 0 1.2em
border-color: $theme transparent transparent transparent
@media #{$laptop}
left: calc((100% - 2.4em) / 2)
.c-container
display: flex
flex-direction: column
max-width: 960px
margin: 0 auto
padding: 1em
margin-bottom: 2em
@media #{$laptop}
flex-direction: row
padding: 3em
margin-bottom: 4em
h1
position: relative
text-transform: uppercase
font-size: 1.4em
letter-spacing: 0.1em
color: #686A66
&:before
content: ''
position: absolute
width: 10%
height: 5px
bottom: -0.5em
left: 0
background: $btn
.c-contact
display: flex
flex-direction: column
align-items: flex-start
justify-content: center
padding: 1em 0
@media #{$laptop}
max-width: 50%
border-right: solid 3px #F8BD55
padding: 2em
h1
margin: 0 0 1.5em 0
p
margin-top: 0
margin-bottom: 1em
color: #7E7E7E
.c-form
max-width: 500px
margin: 0
@media #{$laptop}
padding: 1em
margin: 0 auto
label
margin-bottom: 1em
.c-form-group
display: flex
align-items: center
justify-content: flex-start
margin: 0.8em 0 1em 0
label[for="email"] > .c-form-label
margin: 0 0 0.2em 0
.c-form-label
display: block
margin: 1em 0 0.2em 0
font-size: 0.8em
text-transform: uppercase
color: rgba(25,25,25,0.8)
abbr
color: $alert
text-decoration: none
.c-form-input
display: block
border-color: rgba(25,25,25,0.1)
border-width: 0 0 2px 0
padding: 0.2em 2em 0.2em 0
// margin-bottom: 1em
transition: border-color ease 300ms
background-repeat: no-repeat
background-size: 20px 20px
background-position: 99% 50%
width: 100%
&:focus
border-color: #03A9F4
&[aria-invalid="false"]
//invalid
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%234CAF50' d='M9.984 17.016l9-9-1.406-1.453-7.594 7.594-3.563-3.563-1.406 1.406zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
margin-bottom: 0
&[aria-invalid="true"]
//valid
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%23F44336' d='M17.016 15.609l-3.609-3.609 3.609-3.609-1.406-1.406-3.609 3.609-3.609-3.609-1.406 1.406 3.609 3.609-3.609 3.609 1.406 1.406 3.609-3.609 3.609 3.609zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
border-color: $alert
margin-bottom: 0
&__length
font-size: 0.7em
color: #757575
float: right
clear: both
margin-top: 0.2em
textarea.c-form-input
background-position: 99% 0
&[aria-invalid="false"]
//invalid
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%234CAF50' d='M9.984 17.016l9-9-1.406-1.453-7.594 7.594-3.563-3.563-1.406 1.406zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
margin-bottom: 0
&[aria-invalid="true"]
//valid
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%23F44336' d='M17.016 15.609l-3.609-3.609 3.609-3.609-1.406-1.406-3.609 3.609-3.609-3.609-1.406 1.406 3.609 3.609-3.609 3.609 1.406 1.406 3.609-3.609 3.609 3.609zM12 2.016c5.531 0 9.984 4.453 9.984 9.984s-4.453 9.984-9.984 9.984-9.984-4.453-9.984-9.984 4.453-9.984 9.984-9.984z'></path></svg>")
border-color: $alert
.c-form-checkbox
appearance: none
-webkit-appearance: none
width: 1em
height: 1em
border: solid $text 2px
margin-right: 0.2em
border-color: #efefef
transition: ease 400ms
background-size: 0 0
cursor: pointer
&:checked
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'><path fill='%23FB9375' d='M9 16.172l10.594-10.594 1.406 1.406-12 12-5.578-5.578 1.406-1.406z'></path></svg>")
background-size: 20px 20px
background-position: 50% 50%
background-repeat: no-repeat
& + .c-form-label
margin: 0
.c-form-submit
background-color: $btn
font-size: 0.8em
font-weight: bold
letter-spacing: 0.1em
color: white
border: 0
padding: 0.5em 1em
margin-top: 1em
cursor: pointer
transition: ease 400ms
text-align: center
text-transform: uppercase
&:hover
opacity: 0.9
.c-thankyou
padding: 1em 0
opacity: 1
animation: fade 600ms forwards
@media #{$laptop}
padding: 2em
&.u-hide
animation: none
footer
p
font-size: 0.8em
text-align: center
padding: 0.7em
.u-alert
display: block
height: 0
opacity: 0
height: 0
overflow: hidden
transition: ease 400ms
font-size: 0.8em
&.invalid
color: $alert
opacity: 1
height: auto
max-height: none
margin-top: 0.3em
.u-hide
display: none
@keyframes fade
0%
opacity: 0
100%
opacity: 1
View Compiled
(() => {
let timer; //timer for requestAnimationFrame in debounce func
let length = 0; //text length for message field
const inputList = Array.prototype.slice.call(document.getElementsByTagName('input')).filter(item => item.type !== 'submit' && item.type !== 'checkbox');
const input = inputList.concat(Array.prototype.slice.call(document.getElementsByTagName('textarea')));
//valid each item and set error message
function isValid(input) {
const target = input.id ? input.id : input.target.id;
const valid = document.getElementById(target).validity.valid;
if (valid) {
document.getElementById(`${target}-error`).classList.remove('invalid');
document.getElementById(`${target}-error`).removeAttribute('role');
document.getElementById(target).setAttribute('aria-invalid', 'false');
} else {
document.getElementById(`${target}-error`).classList.add('invalid');
document.getElementById(`${target}-error`).setAttribute('role', 'alert');
document.getElementById(target).setAttribute('aria-invalid', 'true');
console.log(document.getElementById(target));
}
if (document.getElementById('form-message').value.length !== length) {
length = document.getElementById('form-message').value.length;
document.getElementById('form-message-length').innerText = length;
}
return valid;
}
//valid all items and return all are valid or not
function validAll(arr) {
let count = 0;
console.log(typeof arr);
if (typeof arr !== 'object') {
return isValid(arr);
} else {
arr.forEach(function (ele) {
if (isValid(ele)) {
count++;
}
});
}
return count === arr.length;
}
function formSubmit(e) {
e.preventDefault();
if (validAll(input)) {
console.log('valid');
document.getElementById('form-submit-error').classList.remove('invalid');
//show thank you message after submission
document.getElementById('form').classList.add('u-hide');
document.getElementById('form-thankyou').classList.remove('u-hide');
} else {
console.log('invalid');
document.getElementById('form-submit-error').classList.add('invalid');
}
}
//debounce func using RAF
function debounce(e = null, func) {
const raf = requestAnimationFrame || mozRequestAnimationFrame ||
webkitRequestAnimationFrame || msRequestAnimationFrame;
const caf = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
if (timer) {
timer = caf(timer);
}
timer = raf(function (timestamp) {
func(e);
return timestamp;
})
}
(() => {
//custom event polyfill for checking autocomplete / prefill input in IE11 from MDN
(function () {
if (typeof window.CustomEvent === "function") return false;
function CustomEvent(event, params) {
params = params || {
bubbles: false,
cancelable: false,
detail: undefined
};
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
input.forEach(item => {
if (item.type !== 'submit' && item.type !== 'checkbox') {
//add event listener for input
item.addEventListener('input', function (e) {
debounce(e, isValid)
})
if (item.value !== '') {
//if input is already prefilled, check its validity
const initCheck = new CustomEvent('initial');
item.addEventListener('initial', isValid);
item.dispatchEvent(initCheck);
} else {
//remove attribute label to hide visual warning, like red border or red icons, as it is not prefilled
item.removeAttribute('aria-invalid');
}
}
})
document.getElementById('form-submit').addEventListener('click', formSubmit);
})();
})();
View Compiled
This Pen doesn't use any external JavaScript resources.