<!--[if IE 9]>
<style>
body {
padding-top: 5em;
}
.hosted-field--label {
top: -1.2em;
}
.form-controls__steps {
top: -1.2em;
}
</style>
<![endif]-->
<div class="container">
<div class="container-wrap per">
<div class="form-controls__steps">1/4</div>
<nav class="form-controls">
<a href="" class="form-controls__prev form-controls--hidden">
<svg width="19" height="32" viewBox="0 0 19 32" xmlns="http://www.w3.org/2000/svg"><title>next</title><path fill="#ffffff" d="M5.657 15.556L18.385 2.828 15.555 0 0 15.556l15.556 15.557 2.83-2.83" fill-rule="evenodd"/></svg>
</a>
<a href="" class="form-controls__next form-controls--hidden">
<svg width="19" height="32" viewBox="0 0 19 32" xmlns="http://www.w3.org/2000/svg"><title>prev</title><path fill="#ffffff" d="M12.727 15.556L0 2.828 2.828 0l15.557 15.556L2.828 31.113 0 28.283" fill-rule="evenodd"/></svg>
</a>
</nav>
<form action="/" method="post" id="cardForm">
<div class="field-container">
<label class="hosted-field--label " for="card-number">Card Number
</label>
<div class="hosted-field" id="card-number"></div>
</div>
<div class="field-container field-container--hidden">
<label class="hosted-field--label " for="expiration-date">
Exp (MM/YY)
</label>
<div class="hosted-field" id="expiration-date"></div>
</div>
<div class="field-container field-container--hidden">
<label class="hosted-field--label " for="cvv">
CVV
</label>
<div class="hosted-field" id="cvv"></div>
</div>
<div class="field-container field-container--hidden field-container--button">
<input id="button-pay" type="submit" value="Pay" />
</div>
</form>
<div class="form-info">
<p class="field-message">Let's add your card number.</p>
</div>
</div>
</div>
/*----- VARIABLES -----*/
$primary: #282828;
$success: #4CAF50;
$error: #f44336;
$small-screen: 467px;
$bouncy: cubic-bezier(.20, 1.3, .7, 1);
/*----- GENERAL -----*/
*,
*:before,
*:after {
box-sizing: inherit;
}
body,
html {
overflow: hidden;
height: 100%;
background-color: $primary;
background: linear-gradient(185grad, darken($primary, 20%), $primary) ;
color: lighten($primary, 85%);
font-family: 'Roboto Mono', monospace;
font-weight: 300;
@media (max-width: $small-screen) {
font-size: 85%;
}
}
html {
box-sizing: border-box;
}
a {
text-decoration: none;
font-size: 2em;
}
/*----- POSITIONING -----*/
.container {
display: flex;
width: 80%;
margin: 0 auto;
flex-direction: column;
justify-content: center;
height: 100%;
perspective: 100;
position: relative;
@media (max-width: $small-screen) {
width: 90%;
}
}
#cardForm {
height: 5em;
width: 100%;
height: 5.5em;
margin-bottom: 1em;
position: relative;
transform: translateX(0em);
}
/*----- HF CONTAINERS -----*/
.field-container {
position: absolute;
width: 100%;
border: 1px solid #fff;
z-index: 2;
opacity: 1;
transition: all 500ms $bouncy;
-webkit-backface-visibility: hidden;
transform-style: preserve-3d;
transform-origin: bottom;
transition: transform 0.5s $bouncy, opacity 0.5s;
opacity: 1;
}
.field-container:nth-child(1) {
animation: inputIntro 0.5s $bouncy;
}
.field-container--hidden {
opacity: 0;
transform: translate(0em, 0em) rotateX(180deg);
z-index: -1;
}
.field-container--button {
border: 0;
}
.hosted-field {
height: 5.5em;
width: 100%;
display: block;
padding-left: 1em;
}
/*----- HF LABELS -----*/
.hosted-field--label {
color: #FFF;
position: absolute;
top: 0.9em;
left: 0.5em;
transition: transform 0.2s $bouncy, color 0.2s;
transform-origin: 0 0;
font-size: 2em;
line-height: 1;
}
.hosted-field--label--moved,
.not-empty {
transform: scale(0.8) translate(0em, -3em);
transition: transform 0.2s $bouncy, color 0.2s;
color: #fff;
}
/*----- HF MESSAGES -----*/
.field-message {
font-size: 1em;
margin: 1em;
opacity: .3;
@media (max-width: $small-screen) {
margin: 0;
}
}
.field-message--error {
color: $error;
}
/*----- HF SUBMIT -----*/
#button-pay {
-webkit-appearance: none;
width: 100%;
border: 0;
text-align: center;
font-size: 2em;
padding: 0.9em;
color: #000;
background: #fff;
cursor: pointer;
}
/*----- HF CONTROLS -----*/
.form-controls__steps {
font-size: 1.5em;
position: absolute;
right: 1em;
transform: translateY(-1.9em);
opacity: .3;
}
.form-controls {
position: absolute;
right: 0;
z-index: 5;
animation: arrowIntroScale 0.3s 0.4s $bouncy backwards;
transition: transform 0.3s $bouncy;
@media (max-width: $small-screen) {
right: 0.5em;
}
a {
display: inline-block;
padding: 1em 0.5em;
transform: scale(0.8);
transition: transform 0.3s $bouncy;
@media (max-width: $small-screen) {
padding: 0.7em 0.1em;
transform: scale(0.6);
}
}
a:hover {
transform: scale(0.9);
transition: transform 0.1s $bouncy;
}
.form-controls--hidden {
transform: scale(0);
transition: transform 0.3s $bouncy;
}
.form-controls--hidden:hover {
transform: scale(0);
}
}
.form-controls--back {
transition: transform 0.2s $bouncy;
transform: translateX(2em);
}
.form-controls--end {
transition: transform 0.2s $bouncy;
transform: translateY(-5em) translateX(-3.5em);
}
/*----- BT CLASSES -----*/
.braintree-hosted-fields-valid {
background: rgba($success, 0.5);
animation: success 0.5s $bouncy;
}
.braintree-hosted-fields-invalid {
background: rgba($error, 0.5);
color: #fff;
animation: error 0.5s $bouncy;
}
/*----- ANIMATIONS -----*/
@keyframes inputIntro {
0% {
transform: translate(0, 0.2em) rotateX(90deg) scale(0.9);
}
100% {
transform: translate(0, 0) rotateX(0) scale(1);
}
}
@keyframes arrowIntroScale {
0% {
transform: translate(-1em, 0) scale(0);
}
100% {
transform: translate(0, 0) scale(1);
}
}
@keyframes error {
0% {
background: $primary;
transform: scale(1);
}
50% {
background: rgba($error, 1);
transform: scale(1.1);
}
100% {
background: rgba($error, 0.5);
transform: scale(1);
}
}
@keyframes success {
0% {
background: $primary;
transform: scale(1);
}
50% {
background: darken($success, 10%);
transform: scale(1.1);
}
100% {
background: rgba($success, 0.5);
transform: scale(1);
}
}
View Compiled
var form = document.querySelector('#cardForm');
// Input switcher
var formItems = [];
var currentFormItem = 0;
$('.field-container').each(function() {
formItems.push(this);
})
// Add the functionality for what happens when people will click on next
function formControlNext() {
$(formItems[currentFormItem]).addClass('field-container--hidden');
$(formItems[currentFormItem + 1]).removeClass('field-container--hidden');
currentFormItem = currentFormItem + 1;
checkFormVisibility();
changeStepperNumber();
hideNext();
return false;
}
function hideNext() {
if (!$(formItems[currentFormItem + 1]).find('.hosted-field').hasClass('hosted-field')) {
$('.form-controls__next').addClass('form-controls--hidden');
}
$('.form-controls__prev').addClass('form-controls--back');
}
function formControlPrev() {
$(formItems[currentFormItem]).addClass('field-container--hidden');
$(formItems[currentFormItem - 1]).removeClass('field-container--hidden');
currentFormItem = currentFormItem - 1;
checkFormVisibility();
changeStepperNumber();
}
function showNext() {
$('.form-controls__next').removeClass('form-controls--hidden');
$('.form-controls__prev').removeClass('form-controls--back');
}
$('.form-controls__next').click(function() {
formControlNext();
return false;
})
$('.form-controls__prev').click(function() {
formControlPrev();
return false;
})
// Update the number of steps and update the content to match input
function changeStepperNumber() {
if (currentFormItem === 3) {
$('.form-controls__steps').text('4 / 4');
$('.field-message').text('Time to buy that sweet sweet bag.');
$('.form-controls').addClass('form-controls--end');
} else if (currentFormItem === 2) {
$('.form-controls__steps').text('3 / 4');
$('.field-message').text('This is on the back of your card.');
$('.form-controls').removeClass('form-controls--end');
} else if (currentFormItem === 1) {
$('.form-controls__steps').text('2 / 4');
$('.field-message').text('When will your card expire?');
} else {
$('.form-controls__steps').text('1 / 4');
$('.field-message').text('Let\'s add your card number.');
}
}
// Show/hide the appropriate controls
function checkFormVisibility() {
if (currentFormItem === 0) {
$('.form-controls__prev').addClass('form-controls--hidden');
} else {
$('.form-controls__prev').removeClass('form-controls--hidden');
}
if (currentFormItem === 3) {
$('.form-controls__next').addClass('form-controls--hidden');
} else {
$('.form-controls__next').removeClass('form-controls--hidden');
}
}
// Create Braintree components
braintree.client.create({
authorization: 'sandbox_g42y39zw_348pk9cgf3bgyw2b'
}, function(err, client) {
if (err) {
console.error(err);
return;
}
braintree.hostedFields.create({
client: client,
styles: {
'input': {
'font-size': '2em',
'font-weight': '300',
'font-family': 'sans-serif',
'color': '#fff'
},
':focus': {
'color': '#fff'
},
'.invalid': {
'color': '#fff'
},
'@media screen and (max-width: 361px)': {
'input': {
'font-size': '1em'
}
}
},
fields: {
number: {
selector: '#card-number'
},
cvv: {
selector: '#cvv'
},
expirationDate: {
selector: '#expiration-date'
}
}
}, function(err, hostedFields) {
if (err) {
console.error(err);
return;
}
hostedFields.on('validityChange', function(event) {
var field = event.fields[event.emittedBy];
if (field.isValid) {
// Show Next button if inputs are valid
showNext();
// Update message to reflect success
$('.field-message').text('Nice! Let\'s move on…');
} else if (!field.isPotentiallyValid) {
// Hide next button
$('.form-controls__next').addClass('form-controls--hidden');
// Change the top message based on the input error
switch ($(field.container).attr('id')) {
case 'card-number':
$('.field-message').text('Please check if you typed the correct card number.');
break;
case 'expiration-date':
$('.field-message').text('Please check your expiration date.');
break;
case 'cvv':
$('.field-message').text('Please check your security code.');
break;
}
} else {
switch ($(field.container).attr('id')) {
case 'card-number':
$('.field-message').text('Let\'s add your card number.');
break;
case 'expiration-date':
$('.field-message').text('When will your card expire?');
break;
case 'cvv':
$('.field-message').text('This is on the back of your card.');
break;
}
}
});
hostedFields.on('focus', function(event) {
var field = event.fields[event.emittedBy];
$(field.container).prev('.hosted-field--label').addClass('hosted-field--label--moved');
$(field.container).parent().addClass('field-container--active');
});
hostedFields.on('blur', function(event) {
var field = event.fields[event.emittedBy];
$(field.container).prev('.hosted-field--label').removeClass('hosted-field--label--moved');
$(field.container).parent().removeClass('field-container--active');
});
hostedFields.on('empty', function(event) {
var field = event.fields[event.emittedBy];
$(field.container).prev('.hosted-field--label').removeClass('not-empty');
});
hostedFields.on('notEmpty', function(event) {
var field = event.fields[event.emittedBy];
$(field.container).prev('.hosted-field--label').addClass('not-empty');
});
form.addEventListener('submit', function(event) {
event.preventDefault();
hostedFields.tokenize(function(err, payload) {
if (err) {
console.error(err);
return;
}
// This is where you would submit payload.nonce to your server
alert('Submit your nonce to your server here!');
});
});
});
});
This Pen doesn't use any external CSS resources.