---
id: layout-3
title: Layout 3 — Stripe-style Two-Column
sidebar_label: Stripe-style Two-Column Example
sidebar_position: 3
description: Order summary and payment form side by side with preCompleteHook demo.
---

import {
  CodeBlock,
  ComponentBox,
  setUpMocks,
  getWebcomponentsVersion,
} from '../../helpers';
import '@justifi/webcomponents/dist/module/justifi-modular-checkout';
import '@justifi/webcomponents/dist/module/justifi-card-form';
import '@justifi/webcomponents/dist/module/justifi-card-billing-form-simple';
import '@justifi/webcomponents/dist/module/justifi-save-new-payment-method';
import './layout-3.css';

{setUpMocks()}

A complete checkout form example that demonstrates a modern two-column payment layout with order summary and payment form side by side. This example showcases how to integrate the `justifi-modular-checkout` wrapper with `justifi-card-form` and `justifi-card-billing-form-simple` components to create a professional payment experience.

The layout includes:

- **Header Bar**: Back arrow, brand name, and test mode indicator
- **Left Column**: Order summary with product details, pricing breakdown, and footer
- **Right Column**: Payment form with email, card details, billing address, and submit button
- **Card Form**: Secure iframe inputs for card number, expiration, and CVV
- **Billing Form**: ZIP code input for billing information (using justifi-card-billing-form-simple)

This example uses CSS parts to style the web components consistently with the overall design theme and demonstrates proper integration of the modular checkout components, including the `preCompleteHook` for custom validation or server updates before submission.

## Example Usage

<ComponentBox>
  <justifi-modular-checkout auth-token="authToken" checkout-id="cho_123">
    <div
      dangerouslySetInnerHTML={{
        __html: `
    <div class="checkout-container">
      <div class="checkout-header">
        <div class="checkout-brand">
          <span class="checkout-back-arrow">←</span>
          <span class="checkout-brand-name">JustiFi Store</span>
        </div>
      </div>
      <div class="checkout-main-container">
        <div class="checkout-order-summary">
          <div class="checkout-pay-header">
            <h1 class="checkout-pay-title">Pay JustiFi Store</h1>
            <div class="checkout-pay-amount">$39.99</div>
          </div>
          <div class="checkout-product-item">
            <div class="checkout-product-image">📚</div>
            <div class="checkout-product-details">
              <div class="checkout-product-name">Fintech Deployhandbook Test</div>
              <div class="checkout-product-description">How to deploy Fintech app...</div>
            </div>
            <div class="checkout-product-price">$39.99</div>
          </div>
          <div class="checkout-summary-breakdown">
            <div class="checkout-summary-row">
              <span>Subtotal</span>
              <span>$39.99</span>
            </div>
            <div class="checkout-summary-row tax">
              <div class="checkout-tax-info">
                <span>Tax</span>
                <span class="checkout-tax-icon">ⓘ</span>
              </div>
              <span class="checkout-tax-placeholder">Enter address to calculate</span>
            </div>
            <div class="checkout-summary-row total">
              <span>Total due</span>
              <span>$39.99</span>
            </div>
          </div>
          <div class="checkout-footer">
            <div class="checkout-powered-by">
              Powered by <span class="checkout-justifi-text">JustiFi</span>
            </div>
            <div class="checkout-footer-links">
              <a href="#" class="checkout-footer-link">Terms</a>
              <a href="#" class="checkout-footer-link">Privacy</a>
            </div>
          </div>
        </div>
        <div class="checkout-payment-form">
          <h2 class="checkout-form-title">Pay with card</h2>
          <div class="checkout-form-field">
            <label class="checkout-form-label">Email</label>
            <input type="email" placeholder="Enter your email" class="checkout-form-input" />
          </div>
          <div class="checkout-form-field">
            <justifi-card-form></justifi-card-form>
            <justifi-card-billing-form-simple></justifi-card-billing-form-simple>
          </div>
          <div class="checkout-form-field">
            <label class="checkout-form-label">Name on card</label>
            <input type="text" placeholder="Enter cardholder name" class="checkout-form-input" />
          </div>
          <div class="checkout-form-field">
            <label class="checkout-form-label">Billing address</label>
            <div style="margin-bottom: 45px;">
              <select class="checkout-form-select">
                <option>United States</option>
                <option>Canada</option>
              </select>
            </div>
            <div style="margin-bottom: 15px;">
              <input type="text" placeholder="Address" class="checkout-form-input" />
            </div>
            <a href="#" class="checkout-manual-link">Enter address manually</a>
          </div>
          <div class="checkout-checkbox-container">
            <justifi-save-new-payment-method label="Save this for next time"></justifi-save-new-payment-method>
          </div>
          <button class="checkout-pay-button" id="submit-button">
            Pay
          </button>
        </div>
      </div>
    </div>
    `,
      }}
    />
  </justifi-modular-checkout>
</ComponentBox>

<CodeBlock>{`<!DOCTYPE html>
<html dir="ltr" lang="en">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
  <title>justifi-modular-checkout</title>

  <script type="module" src="https://cdn.jsdelivr.net/npm/@justifi/webcomponents@${getWebcomponentsVersion()}/dist/webcomponents/webcomponents.esm.js"></script>

<script
  nomodule
  src="https://cdn.jsdelivr.net/npm/@justifi/webcomponents@${getWebcomponentsVersion()}/dist/webcomponents/webcomponents.js"
></script>

  <style>
    .checkout-container * {
      display: block;
      box-sizing: border-box;
    }
    .checkout-container {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
      margin: 0;
      padding: 0;
      background-color: #f8f9fa;
      color: #333;
      min-height: 100vh;
    }
    .checkout-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 20px 40px;
      background-color: white;
      border-bottom: 1px solid #e0e0e0;
    }
    .checkout-brand {
      display: flex;
      align-items: center;
      gap: 10px;
    }
    .checkout-back-arrow { font-size: 20px; }
    .checkout-brand-name { font-size: 18px; font-weight: 500; }
    .checkout-main-container {
      display: flex;
      max-width: 1200px;
      margin: 0 auto;
      padding: 40px 20px;
      gap: 40px;
    }
    .checkout-order-summary {
      display: flex;
      flex-direction: column;
      gap: 30px;
      flex: 0 0 45%;
      padding: 15px;
    }
    .checkout-pay-header { margin-bottom: 30px; }
    .checkout-pay-title {
      font-size: 24px;
      font-weight: 600;
      color: #333;
      margin: 0 0 10px 0;
    }
    .checkout-pay-amount {
      font-size: 32px;
      font-weight: bold;
      color: #333;
    }
    .checkout-product-item {
      display: flex;
      align-items: center;
      gap: 15px;
      margin-bottom: 30px;
      padding-bottom: 20px;
      border-bottom: 1px solid #e0e0e0;
    }
    .checkout-product-image {
      width: 60px;
      height: 80px;
      background-color: #f8f9fa;
      border: 1px solid #e0e0e0;
      border-radius: 4px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 12px;
      color: #666;
    }
    .checkout-product-details { flex: 1; }
    .checkout-product-name {
      font-weight: 500;
      color: #333;
      margin-bottom: 5px;
    }
    .checkout-product-description { font-size: 14px; color: #666; }
    .checkout-product-price { font-weight: 600; color: #333; }
    .checkout-summary-breakdown {
      display: flex;
      flex-direction: column;
      gap: 10px;
      margin-bottom: 30px;
    }
    .checkout-summary-row {
      display: flex;
      justify-content: space-between;
      margin-bottom: 10px;
      font-size: 14px;
    }
    .checkout-summary-row.tax { align-items: center; }
    .checkout-tax-info {
      display: flex;
      align-items: center;
      gap: 5px;
    }
    .checkout-tax-icon { font-size: 12px; color: #666; }
    .checkout-tax-placeholder { color: #666; }
    .checkout-summary-row.total {
      font-size: 16px;
      font-weight: bold;
      color: #333;
      padding-top: 10px;
      border-top: 1px solid #e0e0e0;
    }
    .checkout-footer {
      margin-top: auto;
      font-size: 12px;
      color: #666;
    }
    .checkout-powered-by { margin-bottom: 10px; }
    .checkout-justifi-text { font-weight: 600; }
    .checkout-footer-links { display: flex; gap: 20px; }
    .checkout-footer-link {
      color: #007bff;
      text-decoration: none;
    }
    .checkout-form-field justifi-card-form { margin-bottom: 15px; }
    .checkout-payment-form {
      display: flex;
      flex-direction: column;
      gap: 15px;
      flex: 0 0 50%;
      background-color: white;
      border-radius: 8px;
      padding: 30px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }
    .checkout-form-title {
      font-size: 24px;
      font-weight: 600;
      color: #333;
      margin: 0 0 30px 0;
    }
    .checkout-form-field { margin-bottom: 25px; }
    .checkout-form-label {
      display: block;
      margin-bottom: 8px;
      font-size: 14px;
      font-weight: 500;
      color: #333;
    }
    .checkout-form-input {
      width: 100%;
      padding: 12px 15px;
      border: 1px solid #e0e0e0;
      border-radius: 6px;
      font-size: 14px;
      background-color: white;
    }
    .checkout-form-select {
      width: 100%;
      padding: 12px 15px;
      border: 1px solid #e0e0e0;
      border-radius: 6px;
      font-size: 14px;
      background-color: white;
      color: #333;
    }
    .checkout-manual-link {
      color: #007bff;
      text-decoration: none;
      font-size: 14px;
    }
    .checkout-checkbox-container { margin-bottom: 30px; }
    .checkout-pay-button {
      width: 100%;
      background-color: #007bff;
      color: white;
      border: none;
      padding: 15px;
      border-radius: 6px;
      font-size: 16px;
      font-weight: 600;
      cursor: pointer;
    }
    .checkout-pay-button:hover { background-color: #0056b3; }
    ::part(font-family) {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    }
    ::part(color) { color: #333; }
    ::part(background-color) { background-color: white; }
    ::part(input) {
      border-color: #e0e0e0;
      border-width: 1px;
      border-radius: 6px;
      border-style: solid;
      box-shadow: none;
      font-size: 14px;
      font-weight: normal;
      line-height: 1.5;
      padding: 12px 15px;
      background-color: white;
    }
    ::part(input-focused) {
      border-color: #007bff;
      box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.1);
    }
    ::part(input-invalid) {
      border-color: #dc3545;
      box-shadow: 0 0 0 2px rgba(220, 53, 69, 0.1);
    }
    ::part(label) {
      font-size: 14px;
      font-weight: 500;
      color: #333;
      margin-bottom: 8px;
    }
    ::part(button) {
      padding: 12px 15px;
      font-size: 14px;
      box-shadow: none;
      border-radius: 6px;
      line-height: 1.5;
      text-transform: none;
    }
    ::part(button-primary) {
      color: #ffffff;
      background-color: #007bff;
      border-color: #007bff;
    }
    ::part(button-primary):hover {
      background-color: #0056b3;
      border-color: #0056b3;
      color: #ffffff;
    }
  </style>

</head>

<body>
  <justifi-modular-checkout auth-token="authToken" checkout-id="cho_123">
    <div class="checkout-container">
      <div class="checkout-header">
        <div class="checkout-brand">
          <span class="checkout-back-arrow">←</span>
          <span class="checkout-brand-name">JustiFi Store</span>
        </div>
      </div>
      <div class="checkout-main-container">
        <div class="checkout-order-summary">
          <div class="checkout-pay-header">
            <h1 class="checkout-pay-title">Pay JustiFi Store</h1>
            <div class="checkout-pay-amount">$39.99</div>
          </div>
          <div class="checkout-product-item">
            <div class="checkout-product-image">📚</div>
            <div class="checkout-product-details">
              <div class="checkout-product-name">
                Fintech Deployhandbook Test
              </div>
              <div class="checkout-product-description">
                How to deploy Fintech app...
              </div>
            </div>
            <div class="checkout-product-price">$39.99</div>
          </div>
          <div class="checkout-summary-breakdown">
            <div class="checkout-summary-row">
              <span>Subtotal</span>
              <span>$39.99</span>
            </div>
            <div class="checkout-summary-row tax">
              <div class="checkout-tax-info">
                <span>Tax</span>
                <span class="checkout-tax-icon">ⓘ</span>
              </div>
              <span class="checkout-tax-placeholder">
                Enter address to calculate
              </span>
            </div>
            <div class="checkout-summary-row total">
              <span>Total due</span>
              <span>$39.99</span>
            </div>
          </div>
          <div class="checkout-footer">
            <div class="checkout-powered-by">
              Powered by <span class="checkout-justifi-text">JustiFi</span>
            </div>
            <div class="checkout-footer-links">
              <a href="#" class="checkout-footer-link">
                Terms
              </a>
              <a href="#" class="checkout-footer-link">
                Privacy
              </a>
            </div>
          </div>
        </div>
        <div class="checkout-payment-form">
          <h2 class="checkout-form-title">Pay with card</h2>
          <div class="checkout-form-field">
            <label class="checkout-form-label">Email</label>
            <input
              type="email"
              placeholder="Enter your email"
              class="checkout-form-input"
            />
          </div>
          <div class="checkout-form-field">
            <justifi-card-form></justifi-card-form>
            <justifi-card-billing-form-simple></justifi-card-billing-form-simple>
          </div>
          <div class="checkout-form-field">
            <label class="checkout-form-label">Name on card</label>
            <input
              type="text"
              placeholder="Enter cardholder name"
              class="checkout-form-input"
            />
          </div>
          <div class="checkout-form-field">
            <label class="checkout-form-label">Billing address</label>
            <div style="margin-bottom: 45px;">
              <select class="checkout-form-select">
                <option>United States</option>
                <option>Canada</option>
              </select>
            </div>
            <div style="margin-bottom: 15px;">
              <input
                type="text"
                placeholder="Address"
                class="checkout-form-input"
              />
            </div>
            <a href="#" class="checkout-manual-link">
              Enter address manually
            </a>
          </div>
          <div class="checkout-checkbox-container">
            <justifi-save-new-payment-method label="Save this for next time"></justifi-save-new-payment-method>
          </div>
          <button class="checkout-pay-button" id="submit-button">
            Pay
          </button>
        </div>
      </div>
    </div>
  </justifi-modular-checkout>
</body>

<script>
  (function() {
    const modularCheckout = document.querySelector('justifi-modular-checkout');
    const submitButton = document.querySelector('#submit-button');

    modularCheckout.preCompleteHook = (state, resolve, reject) => {
      // You could check the payment method type
      // if (state.selectedPaymentMethod?.type === 'new_card') { ... }

      // You could update records on your server before submission
      // await fetch('/api/pre-checkout', {
      //   method: 'POST',
      //   body: JSON.stringify(state)
      // });

      // You could perform custom validation
      // const isValid = myCustomValidation(state);
      // if (isValid) { resolve(state); } else { reject(); }

      // For this example, always proceed
      resolve(state);
    };

    submitButton.addEventListener('click', async () => {
      await modularCheckout.submitCheckout();
    });

    modularCheckout.addEventListener('submit-event', (event) => {
      console.log('Checkout completed successfully!', event.detail);
    });

    modularCheckout.addEventListener('error-event', (event) => {
      console.error('Checkout error:', event.detail);
    });

    modularCheckout.addEventListener('checkout-changed', (event) => {
      console.log('Checkout changed:', event.detail);
    });
  })();
</script>

</html>`}</CodeBlock>
