<form action="//css-tricks.us2.list-manage.com/subscribe/post?u=155f5a9ccc4e24c318130cace&id=197f127a68" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank">
<h2>Subscribe to our mailing list</h2>
<div>
<label for="mce-FNAME">First Name</label>
<input type="text" name="FNAME" id="mce-FNAME">
</div>
<div>
<label for="mce-EMAIL">Email Address</label>
<input type="email" name="EMAIL" id="mce-EMAIL" title="The domain portion of the email address is invalid (the portion after the @)." pattern="^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*(\.\w{2,})+$" required>
</div>
<div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_f2d244c0df42a0431bd08ddea_aeaa9dd034" tabindex="-1" value=""></div>
<div><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
</form>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
font-size: 112.5%;
margin-left: auto;
margin-right: auto;
max-width: 40em;
width: 88%;
}
/**
* Form Styles
*/
label {
display: block;
font-weight: bold;
margin-bottom: 0.5em;
}
.label-normal {
font-weight: normal;
}
.pattern {
color: #808080;
font-size: 0.8em;
font-weight: normal;
}
.supports-color .color,
.supports-date .date,
.supports-time .time,
.supports-month .mont {
display: none;
}
input,
select {
display: inline-block;
font-size: 1em;
margin-bottom: 1em;
padding: 0.25em 0.5em;
width: 100%;
}
[type="checkbox"],
[type="radio"] {
margin-bottom: 0.5em;
width: auto;
}
.button {
background-color: #0088cc;
border: 1px solid #0088cc;
border-radius: 1px;
color: #ffffff;
display: inline-block;
font-size: 0.9375em;
font-weight: normal;
line-height: 1.2;
margin-right: 0.3125em;
margin-bottom: 0.3125em;
padding: 0.5em 0.6875em;
width: auto;
}
.button:active,
.button:focus,
.button:hover {
background-color: #005580;
border-color: #005580;
color: #ffffff;
text-decoration: none;
}
.button:active {
box-shadow: inset 0 0.15625em 0.25em rgba(0, 0, 0, 0.15), 0 1px 0.15625em rgba(0, 0, 0, 0.05);
}
/**
* Errors
*/
.error {
border-color: red;
}
.error-message {
color: red;
font-style: italic;
margin-bottom: 1em;
}
// Add the novalidate attribute when the JS loads
var forms = document.querySelectorAll('.validate');
for (var i = 0; i < forms.length; i++) {
forms[i].setAttribute('novalidate', true);
}
// Validate the field
var hasError = function (field) {
// Don't validate submits, buttons, file and reset inputs, and disabled fields
if (field.disabled || field.type === 'file' || field.type === 'reset' || field.type === 'submit' || field.type === 'button') return;
// Get validity
var validity = field.validity;
// If valid, return null
if (validity.valid) return;
// If field is required and empty
if (validity.valueMissing) return 'Please fill out this field.';
// If not the right type
if (validity.typeMismatch) {
// Email
if (field.type === 'email') return 'Please enter an email address.';
// URL
if (field.type === 'url') return 'Please enter a URL.';
}
// If too short
if (validity.tooShort) return 'Please lengthen this text to ' + field.getAttribute('minLength') + ' characters or more. You are currently using ' + field.value.length + ' characters.';
// If too long
if (validity.tooLong) return 'Please shorten this text to no more than ' + field.getAttribute('maxLength') + ' characters. You are currently using ' + field.value.length + ' characters.';
// If pattern doesn't match
if (validity.patternMismatch) {
// If pattern info is included, return custom error
if (field.hasAttribute('title')) return field.getAttribute('title');
// Otherwise, generic error
return 'Please match the requested format.';
}
// If number input isn't a number
if (validity.badInput) return 'Please enter a number.';
// If a number value doesn't match the step interval
if (validity.stepMismatch) return 'Please select a valid value.';
// If a number field is over the max
if (validity.rangeOverflow) return 'Please select a value that is no more than ' + field.getAttribute('max') + '.';
// If a number field is below the min
if (validity.rangeUnderflow) return 'Please select a value that is no less than ' + field.getAttribute('min') + '.';
// If all else fails, return a generic catchall error
return 'The value you entered for this field is invalid.';
};
// Show an error message
var showError = function (field, error) {
// Add error class to field
field.classList.add('error');
// If the field is a radio button and part of a group, error all and get the last item in the group
if (field.type === 'radio' && field.name) {
var group = field.form.querySelectorAll('[name="' + field.name + '"]');
if (group.length > 0) {
for (var i = 0; i < group.length; i++) {
group[i].classList.add('error');
}
field = group[group.length - 1];
}
}
// Get field id or name
var id = field.id || field.name;
if (!id) return;
// Check if error message field already exists
// If not, create one
var message = field.form.querySelector('.error-message#error-for-' + id );
if (!message) {
message = document.createElement('div');
message.className = 'error-message';
message.id = 'error-for-' + id;
// If the field is a radio button or checkbox, insert error after the label
var label;
if (field.type === 'radio' || field.type ==='checkbox') {
label = field.form.querySelector('label[for="' + id + '"]') || field.parentNode;
if (label) {
label.parentNode.insertBefore( message, label.nextSibling );
}
}
// Otherwise, insert it after the field
if (!label) {
field.parentNode.insertBefore( message, field.nextSibling );
}
}
// Add ARIA role to the field
field.setAttribute('aria-describedby', 'error-for-' + id);
// Update error message
message.innerHTML = error;
// Show error message
message.style.display = 'block';
message.style.visibility = 'visible';
};
// Remove the error message
var removeError = function (field) {
// Remove error class to field
field.classList.remove('error');
// Remove ARIA role from the field
field.removeAttribute('aria-describedby');
// If the field is a radio button and part of a group, remove error from all and get the last item in the group
if (field.type === 'radio' && field.name) {
var group = field.form.querySelectorAll('[name="' + field.name + '"]');
if (group.length > 0) {
for (var i = 0; i < group.length; i++) {
group[i].classList.remove('error');
}
field = group[group.length - 1];
}
}
// Get field id or name
var id = field.id || field.name;
if (!id) return;
// Check if an error message is in the DOM
var message = field.form.querySelector('.error-message#error-for-' + id + '');
if (!message) return;
// If so, hide it
message.innerHTML = '';
message.style.display = 'none';
message.style.visibility = 'hidden';
};
// Listen to all blur events
document.addEventListener('blur', function (event) {
// Only run if the field is in a form to be validated
if (!event.target.form.classList.contains('validate')) return;
// Validate the field
var error = hasError(event.target);
// If there's an error, show it
if (error) {
showError(event.target, error);
return;
}
// Otherwise, remove any existing error message
removeError(event.target);
}, true);
// Check all fields on submit
document.addEventListener('submit', function (event) {
// Only run on forms flagged for validation
if (!event.target.classList.contains('validate')) return;
// Get all of the form elements
var fields = event.target.elements;
// Validate each field
// Store the first field with an error to a variable so we can bring it into focus later
var error, hasErrors;
for (var i = 0; i < fields.length; i++) {
error = hasError(fields[i]);
if (error) {
showError(fields[i], error);
if (!hasErrors) {
hasErrors = fields[i];
}
}
}
// If there are errrors, don't submit form and focus on first element with error
if (hasErrors) {
event.preventDefault();
hasErrors.focus();
}
// Otherwise, let the form submit normally
// You could also bolt in an Ajax form submit process here
}, false);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.