Style Credit Card iFrames
WePay's credit card iFrames allow a high level of customization and styling. We've outlined how to style it in this guide, and you can test it out using this sample:
csshtmljs
#shipping-address {
display: none;
}
<body>
<div class="container">
<ul class="collapsible popout">
<li>
<div class="collapsible-header"><i class="material-icons">shopping_cart</i>Order</div>
<div class="collapsible-body" id="order-body">
<div class="container">
<div class="row">
<img class="responsive-img col m6 materialboxed"
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1671/mop.png" alt="Primo Mop" />
<div class="col m5">
<div class="card-panel blue-grey">
<div class="card-content white-text">
<span class="card-title">Primo Mop</span>
<p>Quantity: 20<br>Price: $15.00 USD</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="card-panel blue-grey">
<div class="card-content white-text center">
<p>Subtotal: 300.00 USD<br>Shipping: $7.50 USD<br>Fees: $2.50 USD</p>
<span class="card-title">Total: $310.00 USD</span>
</div>
</div>
</div>
</div>
</div>
</li>
<li class="active">
<div class="collapsible-header"><i class="material-icons">place</i>Address</div>
<div class="collapsible-body row" id="address-body">
<div class="row">
<div class="col s12">
<div class="card blue-grey">
<div class="card-content white-text">
<span class="card-title">Billing Address</span>
<p>Enter the address associated with your card.</p>
</div>
</div>
</div>
</div>
<div class="container">
<form class="col s12">
<div class="row">
<div class="input-field col s6">
<input placeholder="first name" id="first_name" type="text" class="validate">
<label for="first_name">first name</label>
</div>
<div class="input-field col s6">
<input placeholder="last name" id="last_name" type="text" class="validate">
<label for="last_name">last name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="email" id="email" type="text" class="validate">
<label for="email">email</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input placeholder="street address" id="street_address" type="text" class="validate">
<label for="street_address">street address</label>
</div>
<div class="input-field col s6">
<input placeholder="suite / apt." id="suite" type="text" class="validate">
<label for="suite">suite / apt.</label>
</div>
</div>
<div class="row">
<div class="input-field col s4">
<input placeholder="city" id="city" type="text" class="validate">
<label for="city">city</label>
</div>
<div class="input-field col s4">
<input placeholder="state" id="state" type="text" class="validate">
<label for="state">state</label>
</div>
<div class="input-field col s4">
<input placeholder="zip" id="zip" type="text" class="validate">
<label for="zip">zip</label>
</div>
</div>
</form>
<form action="#">
<p>
<label>
<input type="checkbox" id="same" onclick="showMe('shipping-input')" />
<span>Different from shipping address?</span>
</label>
</p>
</form>
</div>
<form class="col s12" id="shipping-address">
<div class="row">
<div class="col s12">
<div class="card blue-grey">
<div class="card-content white-text">
<span class="card-title">Shipping Address</span>
<p>Enter the address where your order will be shipped.</p>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="input-field col s6">
<input placeholder="first name" id="first_name" type="text" class="validate">
<label for="first_name">first name</label>
</div>
<div class="input-field col s6">
<input placeholder="last name" id="last_name" type="text" class="validate">
<label for="last_name">last name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input placeholder="email" id="email" type="text" class="validate">
<label for="email">email</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input placeholder="street address" id="street_address" type="text" class="validate">
<label for="street_address">street address</label>
</div>
<div class="input-field col s6">
<input placeholder="suite / apt." id="suite" type="text" class="validate">
<label for="suite">suite / apt.</label>
</div>
</div>
<div class="row">
<div class="input-field col s4">
<input placeholder="city" id="city" type="text" class="validate">
<label for="city">city</label>
</div>
<div class="input-field col s4">
<input placeholder="state" id="state" type="text" class="validate">
<label for="state">state</label>
</div>
<div class="input-field col s4">
<input placeholder="zip" id="zip" type="text" class="validate">
<label for="zip">zip</label>
</div>
</div>
</form>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action"
onclick="closeAddress(); openSubmit();">Next
<i class="material-icons right">send</i>
</button>
</div>
</li>
<li id="checkout">
<div class="collapsible-header"><i class="material-icons">credit_card</i>Submit</div>
<div class="collapsible-body" id="submit">
<span>
<div class="container">
<div class="row">
<img class="responsive-img" id="accepted-cards"
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-1671/card-brands.png" border="0"
alt="Accepted Cards" />
</div>
<div class="row">
<div id="credit_card_iframe"></div>
</div>
<div class="row">
<div class="card blue-grey lighten-2">
<div class="card-content white-text">
<p>By clicking submit, you agree to Mop Emporium's <a href="#">refund, cancellation, and return</a>
policy.<br>Orders will be shipped in 2-3 business days, at which time tracking information will be
provided in a confirmation email.</p>
</div>
</div>
</div>
<button class="btn waves-effect waves-light" type="submit" name="action" id="submit-credit-card-button">Submit
<i class="material-icons right">send</i>
</button>
<div id="token"></div>
</div>
</span>
</div>
</li>
</ul>
</div>
<script src="https://cdn.wepay.com/wepay.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</body>
//insert your app ID
var appId = "{{insert-your-app-id}}"
var options = {
custom_style:custom_style,
show_labels:true,
show_placeholders:true,
show_error_messages:true,
show_error_messages_when_unfocused:true,
use_one_liner: false
};
document.addEventListener('DOMContentLoaded', function() {
// initialize materialize collapsible
var collapsibleElement = document.querySelector('.collapsible');
var collapsibleInstance = M.Collapsible.init(collapsibleElement);
// initialize materialize material box
var materialBox = document.querySelectorAll('.materialboxed');
var instances = M.Materialbox.init(materialBox);
// load with address open
collapsibleInstance.open(1);
});
// show shipping address if different
function showMe() {
var box = document.getElementById('same');
var vis = (box.checked) ? "block" : "none";
document.getElementById('shipping-address').style.display = vis;
}
// close address section on "next" click
function closeAddress() {
var elems = document.querySelector('.collapsible');
var instances = M.Collapsible.init(elems);
instances.close(1);
}
// open submit section on "next" click
function openSubmit() {
var elems = document.querySelector('.collapsible');
var instances = M.Collapsible.init(elems);
instances.open(2);
}
// credit card iframe styling
var custom_style = {
'styles': {
'base': {
'color': 'grey',
'border': '1px solid grey',
'border-top': 'none',
'border-right': 'none',
'border-left': 'none',
'font-weight': '200',
'font-family': 'Arial',
'padding': '0px',
'margin-bottom': '5px',
':focus': {
'border': '2px solid #4db6ac',
'border-top': 'none',
'border-right': 'none',
'border-left': 'none'
},
'::placeholder': {
'text-transform': 'lowercase',
'color': '#D3D3D3',
'font-size': '17px'
}
},
'invalid': {
'color': '#CD5C5C',
'border-color': '#CD5C5C'
},
'valid': {
'color': '#4db6ac',
'border-color': '#4db6ac'
},
'labels': {
'base': {
'color': 'gray',
'font-family': 'Arial',
'font-size': '13px',
'font-weight': '1',
'text-transform': 'lowercase',
'padding': '0px',
'padding-left': '0px'
}
},
'errors': {
'invalid': {
'color': '#CD5C5C'
}
}
}
};
if (options.use_one_liner) {
custom_style = {
"styles": {
"cc-logo":{
"base":{
"margin":"12px 12px 7px 12px"
}
},
"cc-mask":{
"base":{
"margin":"12px 12px 7px 12px"
}
},
"cvv-icon":{
"base":{
"display":"none"
}
}
}
}
}
//credit card iframe configs
var myAppId = appId;
var apiVersion = "3.0";
var error = WePay.configure("stage", myAppId, apiVersion);
if (error) {
console.log(error);
}
var iframe_container_id = "credit_card_iframe";
var creditCard = WePay.createCreditCardIframe(iframe_container_id, options);
document.getElementById('submit-credit-card-button').addEventListener('click', function (event) {
creditCard.tokenize()
.then(function (response) {
//get the promise response from the console
console.log('response', JSON.stringify(response));
var node = document.createElement('div');
node.innerHTML = JSON.stringify(response);
document.getElementById('token').appendChild(node);
})
.catch(function (error) {
console.log('error', error);
// Move the focus to the first error
if (Array.isArray(error)) {
let key = error[0].target[0];
creditCard.setFocus(key);
}
// display the response on the page for testing purposes; do not launch with this section
var node = document.createElement('div');
node.innerHTML = JSON.stringify(error);
document.getElementById('token').appendChild(node);
});
});
Create An iFrame
If you haven't already, follow the steps laid out here to initialize the Javascript SDK. Once your page has initialized the SDK, the next step is to define the div in which the credit card iFrame will be injected.
<body> ... <div id="credit-card-iframe"> </div> ... <div id="token"> </div> ... </body>
WePay.createCreditCardIframe()
. The first argument takes the ID of the div in which you wish to inject the iFrame, and the second argument is an optional Javascript object of customizable display options. The object can contain the following keys, all of which are also optional:Key | Default Value | Description |
---|---|---|
custom_style | null | Create an object with additional styling, outlined in detail below to change WePay's default styling. |
show_labels | false | When true , an identifying label will be displayed above each input field. |
show_placeholders | true | When true , identifying placeholder text will be displayed inside each input field. |
show_error_messages | false | When true , an error message will be displayed underneath each invalid input |
show_error_messages_when_unfocused | true | When false , hides any errors messages for invalid inputs when the input is not in focus; when true , error messages persist even when the input field is not in focus. |
WePay recommends sending the optional display options through as follows:
var options = {
'custom_style': '{YOUR-CUSTOM-STYLES}',
'show_labels': true,
'show_placeholders': false,
'show_error_messages': true,
'show_error_messages_when_unfocused': true
}
var iframe_container_id = "credit-card-iframe";
var creditCard = WePay.createCreditCardIframe(credit-card-iframe, options)
Style An iFrame
Next, customize iFrame styling by creating an object which describes thecustom_style
. Use the following classes to globally define input style behavior for default viewing, valid data input, and invalid data input:base
valid
invalid
labels
style behavior by using labels
as a top-level key with base
, valid
, and/or invalid
nested keys.Here is an example of global custom style using the CSS property color
:var custom_style = {
'styles': {
'base': {
'color': 'blue'
},
'invalid': {
'color': 'red'
},
'valid': {
'color': 'green'
},
'labels': {
'base': {
'color': 'gray'
}
}
}
}
Click to see a static rendered instance of the above custom_style
and options
examples
Click to see a static rendered instance of when use_one_liner
in options
is set to true
base
, invalid
, valid
, and labels
classes:Class Name | Notes |
---|---|
cvv-icon | This can only have base.display nested in order to hide the icon. |
cvv-number | |
expiration-month | There is only one label for the expiration date, and label styling should be nested under `expiration_month` if custom styling is desired there. |
expiration-year | Do not apply styling here. |
expiration-slash | When setting base , invalid , and valid styles for this element, the styling will depend on base/invalidity/validity of the expiration month input by the user. So if the month input is invalid, the slash will display the defined invalid styling, if styling is present. |
cc-number | |
errors | Currently, the only accepted properties for styling errors are invalid and color . See the example below to see the accepted method of styling errors. |
Styling specific elements will override global styles when there is a conflict.
Use the following CSS properties and pseudo-classes to customize global and element styling:
appearance
border
border-left
border-right
border-top
border-bottom
border-color
border-radius
box-shadow
color
display
(forcvv-icon
element only)font-size
font-weight
font-family
font-smooth
font-style
font-variant
letter-spacing
line-height
margin
padding
text-decoration
text-shadow
text-transform
transition
width
:hover
:focus
::placeholder
::selection
Note
Pass
margin
, box-shadow
, and width
as pixels, otherwise the inputs may not align with the iFrame correctly.options
and custom_style
objects, as well as element-level and global-level styling:var custom_style = {
'styles': {
'base': {
'color': 'blue',
'border-color': 'blue'
},
'invalid': {
'color': 'red',
'border-color': 'red'
},
'valid': {
'color': 'green',
'border-color': 'green'
},
'labels': {
'base': {
'color': 'gray',
'font-size': '200%'
}
},
'cvv-icon': {
'base': {
'display': 'none'
}
},
'errors': {
'invalid': {
'color': 'blue'
}
}
}
};
var options = {
custom_style: custom_style,
show_labels:true,
show_placeholders:false,
show_error_messages:true,
show_error_messages_when_unfocused:true
};
KEY
is a string that corresponds to the id of the element that should receive focus:creditCard.setFocus(KEY);
Valid keys:
cc-number
cvv-number
expiration-month
expiration-year
If an invalid key is passed, the focus will not move.
The intent of this function is to allow the parent page to move the focus to the first error when errors are present in the form. There should be some additional logic in your code on the parent page to process the errors and choose where to move focus. For example, if there is an error on the parent page, focus should be moved there. However, if the first error is in thecc-number
field, the parent page could call creditCard.setFocus(“cc-number”);
to move focus to the credit card number field.Tokenize An iFrame
Beyond styling, attach a submit handler for your checkout submission form, and, once executed, call thecreditCard
variable's tokenize
function, and extract the token in the response. The response is a Promise.creditCard.tokenize()
.then(function (response) {
console.log('response', response);
var node = document.createElement('div');
node.innerHTML = JSON.stringify(response);
document.getElementById('token').appendChild(node);
})
.catch(function (error) {
console.log('error', error);
var node = document.createElement('div');
node.innerHTML = JSON.stringify(error);
document.getElementById('token').appendChild(node);
});