Style Credit Card iFrames

 

Our 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
Copy
Copied
#shipping-address {
  display: none;
}
Copy
Copied
<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>
Copy
Copied
//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.
Copy
Copied
<body>
...
  <div id="credit-card-iframe"></div>
...
  <div id="token"></div>
...
</body>
From this, we will call 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:
KeyDefault ValueDescription
custom_stylenullCreate an object with additional styling, outlined in detail below to change WePay's default styling.
show_labelsfalseWhen true, an identifying label will be displayed above each input field.
show_placeholderstrueWhen true, identifying placeholder text will be displayed inside each input field.
show_error_messagesfalseWhen true, an error message will be displayed underneath each invalid input
show_error_messages_when_unfocusedtrueWhen 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.
show_error_icontrueWhen false, hides the error exclamation icon (!) that would be rendered next to an error message by default
show_required_asteriskfalseWhen true, renders an asterisk next to the label of each required field. When enabled, the asterisk can be styled like the other specific elements (e.gcvv-icon and cvv-number) bby accessing asterisk.
resize_on_error_messagefalseWhen true, the space at the bottom of the iframe normally reserved for the error message is removed, and the iframe height is dynamically resized when error messages are rendered. Only takes effect when show_error_messages is also true.
custom_required_field_error_message"This field is required"Create string text for the required field error message. The string can have a maximum of 40 characters, and must only contain alphabetical letters.
use_one_linerfalseDisplay all credit card iFrame fields in a single row.

We recommend setting the following optional display keys at minimum:

Copy
Copied
var options = {
  custom_style:custom_style,
  show_labels:true,
  show_placeholders:true,
  show_error_messages:true, 
  show_error_messages_when_unfocused:true,
  show_error_icon: true,
  show_required_asterisk: false,
  resize_on_error_message: false,
  custom_required_field_error_message: '{YOUR-CUSTOM-REQUIRED-FIELD-ERROR-MESSAGE}',
  use_one_liner: false
};

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 the custom_style. Use the following classes to globally define input style behavior for default viewing, valid data input, and invalid data input:
  • base
  • valid
  • invalid
Additionally, you can describe the global 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:
Copy
Copied
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 credit card iframe example
Click to see a static rendered instance of when use_one_liner in options is set to true Have the input boxes for the credit card information be on one line
Style specific elements within the iFrame by using the following classes with nested base, invalid, valid, and labels classes:
Class NameNotes
cvv-iconThis can only have base.display nested in order to hide the icon.
cvv-number
asterisk
expiration-monthThere is only one label for the expiration date, and label styling should be nested under `expiration_month` if custom styling is desired there.
expiration-yearDo not apply styling here.
expiration-slashWhen 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
errorsCurrently, 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 (for cvv-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.
Here's an example using the options and custom_style objects, as well as element-level and global-level styling:
Copy
Copied
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
};
In order to move the focus to a specific input in the iFrame, call the following function where 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 the cc-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 the creditCard variable's tokenize function, and extract the token in the response. The response is a Promise.
Copy
Copied
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);
  });