FORMS

Interactive Secure Checkout Form

A modern secure checkout interface with card and wallet payment options, input validation, payment processing animation and a responsive success state.

SECURE CHECKOUT

Complete Payment

Encrypted
Order total $49.00
USD
Payment method
Enter the cardholder name.
Enter a valid card number.
Check expiry date.
?
Enter a valid CVC.
Your payment information is encrypted and secure.
PAYMENT COMPLETE

Securely Processed!

Your demo payment has been successfully processed.

Amount paid $49.00
HTML
<div class="cr-checkout" data-cr-checkout>
  <div class="cr-checkout__card">

    <div class="cr-checkout__header">

      <div class="cr-checkout__brand">

        <span class="cr-checkout__brand-icon" aria-hidden="true">
          <svg viewBox="0 0 24 24">
            <path d="M12 2 4.5 5.2v5.1c0 5.1 3.1 9.7 7.5 11.7 4.4-2 7.5-6.6 7.5-11.7V5.2L12 2Z"></path>
            <path d="m8.8 12 2.1 2.1 4.5-4.6"></path>
          </svg>
        </span>

        <div>
          <span class="cr-checkout__eyebrow">
            SECURE CHECKOUT
          </span>
          <h2>Complete Payment</h2>
        </div>

      </div>

      <div class="cr-checkout__secure">
        <span class="cr-checkout__secure-dot"></span>
        Encrypted
      </div>

    </div>


    <div class="cr-checkout__summary">

      <div>
        <span class="cr-checkout__summary-label">
          Order total
        </span>
        <strong>$49.00</strong>
      </div>

      <span class="cr-checkout__summary-note">
        USD
      </span>

    </div>


    <fieldset class="cr-checkout__methods">

      <legend>Payment method</legend>

      <div class="cr-checkout__method-grid">

        <label class="cr-checkout__method is-active">

          <input
            type="radio"
            name="cr-payment-method"
            value="card"
            checked
          >

          <span class="cr-checkout__method-icon" aria-hidden="true">
            <svg viewBox="0 0 24 24">
              <rect
                x="2.5"
                y="5"
                width="19"
                height="14"
                rx="2.5"
              ></rect>
              <path d="M2.5 9.5h19"></path>
              <path d="M6 15h4"></path>
            </svg>
          </span>

          <span class="cr-checkout__method-text">
            <strong>Card</strong>
            <small>Visa, Mastercard</small>
          </span>

          <span class="cr-checkout__radio-dot"></span>

        </label>


        <label class="cr-checkout__method">

          <input
            type="radio"
            name="cr-payment-method"
            value="wallet"
          >

          <span class="cr-checkout__method-icon" aria-hidden="true">
            <svg viewBox="0 0 24 24">
              <path d="M4 6.5h14a2 2 0 0 1 2 2v9H5a3 3 0 0 1-3-3v-9a3 3 0 0 1 3-3h12"></path>
              <path d="M16 11h6v4h-6a2 2 0 1 1 0-4Z"></path>
            </svg>
          </span>

          <span class="cr-checkout__method-text">
            <strong>Wallet</strong>
            <small>Quick payment</small>
          </span>

          <span class="cr-checkout__radio-dot"></span>

        </label>

      </div>

    </fieldset>


    <div class="cr-checkout__card-panel">

      <div class="cr-checkout__field">

        <label for="cr-card-name">
          Cardholder name
        </label>

        <div class="cr-checkout__input-wrap">
          <input
            id="cr-card-name"
            type="text"
            autocomplete="cc-name"
            placeholder="Alex Morgan"
          >
        </div>

        <span class="cr-checkout__error">
          Enter the cardholder name.
        </span>

      </div>


      <div class="cr-checkout__field">

        <label for="cr-card-number">
          Card number
        </label>

        <div class="cr-checkout__input-wrap">

          <input
            id="cr-card-number"
            type="text"
            inputmode="numeric"
            autocomplete="cc-number"
            maxlength="19"
            placeholder="4242 4242 4242 4242"
          >

          <span class="cr-checkout__card-mark" aria-hidden="true">
            <span></span>
            <span></span>
          </span>

        </div>

        <span class="cr-checkout__error">
          Enter a valid card number.
        </span>

      </div>


      <div class="cr-checkout__row">

        <div class="cr-checkout__field">

          <label for="cr-card-expiry">
            Expiry
          </label>

          <div class="cr-checkout__input-wrap">
            <input
              id="cr-card-expiry"
              type="text"
              inputmode="numeric"
              autocomplete="cc-exp"
              maxlength="5"
              placeholder="MM/YY"
            >
          </div>

          <span class="cr-checkout__error">
            Check expiry date.
          </span>

        </div>


        <div class="cr-checkout__field">

          <label for="cr-card-cvc">
            CVC
          </label>

          <div class="cr-checkout__input-wrap">

            <input
              id="cr-card-cvc"
              type="password"
              inputmode="numeric"
              autocomplete="cc-csc"
              maxlength="4"
              placeholder="•••"
            >

            <span
              class="cr-checkout__help"
              title="3 or 4 digit security code"
            >
              ?
            </span>

          </div>

          <span class="cr-checkout__error">
            Enter a valid CVC.
          </span>

        </div>

      </div>

    </div>


    <div
      class="cr-checkout__wallet"
      aria-hidden="true"
    >

      <div class="cr-checkout__wallet-icon">

        <svg viewBox="0 0 24 24" aria-hidden="true">
          <path d="M4 6.5h14a2 2 0 0 1 2 2v9H5a3 3 0 0 1-3-3v-9a3 3 0 0 1 3-3h12"></path>
          <path d="M16 11h6v4h-6a2 2 0 1 1 0-4Z"></path>
        </svg>

      </div>

      <div class="cr-checkout__wallet-content">

        <span class="cr-checkout__wallet-label">
          DIGITAL WALLET
        </span>

        <h3>Quick Wallet Payment</h3>

        <p>
          Continue securely using your connected digital wallet.
          No card details are required.
        </p>

        <div class="cr-checkout__wallet-account">

          <span class="cr-checkout__wallet-status">
            <span></span>
            Wallet ready
          </span>

          <strong>$49.00</strong>

        </div>

      </div>

    </div>


    <div class="cr-checkout__form">

      <button
        class="cr-checkout__submit"
        type="button"
      >

        <span class="cr-checkout__submit-default">

          <span class="cr-checkout__pay-text">
            Pay $49.00
          </span>

          <svg viewBox="0 0 24 24" aria-hidden="true">
            <path d="M5 12h14"></path>
            <path d="m14 7 5 5-5 5"></path>
          </svg>

        </span>

        <span class="cr-checkout__submit-loading">
          <span class="cr-checkout__spinner"></span>
          Processing payment...
        </span>

      </button>


      <div class="cr-checkout__trust">

        <svg viewBox="0 0 24 24" aria-hidden="true">
          <rect
            x="5"
            y="10"
            width="14"
            height="10"
            rx="2"
          ></rect>
          <path d="M8 10V7a4 4 0 0 1 8 0v3"></path>
        </svg>

        <span>
          Your payment information is encrypted and secure.
        </span>

      </div>

    </div>


    <div
      class="cr-checkout__success"
      aria-live="polite"
    >

      <div class="cr-checkout__success-icon">
        <svg viewBox="0 0 24 24" aria-hidden="true">
          <path d="m6.5 12.5 3.5 3.5 7.5-8"></path>
        </svg>
      </div>

      <span class="cr-checkout__success-label">
        PAYMENT COMPLETE
      </span>

      <h3>Securely Processed!</h3>

      <p>
        Your demo payment has been successfully processed.
      </p>

      <div class="cr-checkout__success-amount">
        <span>Amount paid</span>
        <strong>$49.00</strong>
      </div>

      <button
        class="cr-checkout__reset"
        type="button"
      >
        Try Again
      </button>

    </div>

  </div>
</div>
CSS
.cr-checkout,
.cr-checkout * {
  box-sizing: border-box;
}

.cr-checkout {
  --cr-bg: #050816;
  --cr-text: #f8fafc;
  --cr-muted: #94a3b8;
  --cr-purple: #8b5cf6;
  --cr-cyan: #22d3ee;
  --cr-green: #34d399;
  --cr-danger: #fb7185;

  width: 100%;
  min-height: 620px;
  padding: 32px 18px;

  display: flex;
  align-items: center;
  justify-content: center;

  color: var(--cr-text);

  font-family:
    Inter,
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    sans-serif;

  background:
    radial-gradient(
      circle at 15% 15%,
      rgba(139, 92, 246, 0.16),
      transparent 32%
    ),
    radial-gradient(
      circle at 85% 85%,
      rgba(34, 211, 238, 0.13),
      transparent 32%
    ),
    var(--cr-bg);

  overflow: hidden;
}

.cr-checkout button,
.cr-checkout input {
  font: inherit;
}

.cr-checkout__card {
  position: relative;

  width: min(100%, 520px);
  padding: 26px;

  background:
    linear-gradient(
      145deg,
      rgba(255, 255, 255, 0.075),
      rgba(255, 255, 255, 0.025)
    ),
    rgba(7, 12, 28, 0.92);

  border: 1px solid rgba(148, 163, 184, 0.16);
  border-radius: 26px;

  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);

  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);

  overflow: hidden;
}

.cr-checkout__card::before,
.cr-checkout__card::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  filter: blur(60px);
  pointer-events: none;
}

.cr-checkout__card::before {
  top: -120px;
  right: -100px;
  width: 220px;
  height: 220px;
  background: rgba(139, 92, 246, 0.2);
}

.cr-checkout__card::after {
  bottom: -110px;
  left: -90px;
  width: 180px;
  height: 180px;
  background: rgba(34, 211, 238, 0.14);
}

.cr-checkout__header {
  position: relative;
  z-index: 2;

  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;

  margin-bottom: 22px;
}

.cr-checkout__brand {
  display: flex;
  align-items: center;
  gap: 13px;
}

.cr-checkout__brand-icon {
  width: 44px;
  height: 44px;
  flex: 0 0 44px;

  display: grid;
  place-items: center;

  color: #ffffff;

  background:
    linear-gradient(
      135deg,
      rgba(139, 92, 246, 0.95),
      rgba(34, 211, 238, 0.9)
    );

  border-radius: 14px;
}

.cr-checkout__brand-icon svg,
.cr-checkout__method-icon svg,
.cr-checkout__wallet-icon svg,
.cr-checkout__trust svg,
.cr-checkout__submit-default svg,
.cr-checkout__success-icon svg {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.cr-checkout__brand-icon svg {
  width: 23px;
  height: 23px;
  stroke-width: 1.8;
}

.cr-checkout__eyebrow {
  display: block;
  margin-bottom: 4px;

  color: var(--cr-cyan);

  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.15em;
}

.cr-checkout__header h2 {
  margin: 0;

  color: #ffffff;

  font-size: 21px;
  font-weight: 750;
}

.cr-checkout__secure {
  display: inline-flex;
  align-items: center;
  gap: 7px;

  padding: 7px 10px;

  color: #cbd5e1;
  background: rgba(255, 255, 255, 0.04);

  border: 1px solid rgba(148, 163, 184, 0.13);
  border-radius: 999px;

  font-size: 11px;
  font-weight: 650;
}

.cr-checkout__secure-dot {
  width: 7px;
  height: 7px;

  background: var(--cr-green);
  border-radius: 50%;

  box-shadow: 0 0 12px rgba(52, 211, 153, 0.75);
}

.cr-checkout__summary {
  position: relative;
  z-index: 2;

  display: flex;
  align-items: center;
  justify-content: space-between;

  margin-bottom: 22px;
  padding: 15px 17px;

  background:
    linear-gradient(
      90deg,
      rgba(139, 92, 246, 0.08),
      rgba(34, 211, 238, 0.06)
    );

  border: 1px solid rgba(148, 163, 184, 0.12);
  border-radius: 16px;
}

.cr-checkout__summary > div {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.cr-checkout__summary-label {
  color: var(--cr-muted);
  font-size: 11px;
  font-weight: 600;
}

.cr-checkout__summary strong {
  color: #ffffff;
  font-size: 22px;
}

.cr-checkout__summary-note {
  color: var(--cr-muted);
  font-size: 11px;
  font-weight: 700;
}

.cr-checkout__methods {
  position: relative;
  z-index: 2;

  margin: 0 0 21px;
  padding: 0;

  border: 0;
}

.cr-checkout__methods legend {
  margin-bottom: 10px;
  padding: 0;

  color: #cbd5e1;

  font-size: 12px;
  font-weight: 650;
}

.cr-checkout__method-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.cr-checkout__method {
  position: relative;

  min-width: 0;
  padding: 13px;

  display: flex;
  align-items: center;
  gap: 10px;

  background: rgba(255, 255, 255, 0.035);

  border: 1px solid rgba(148, 163, 184, 0.13);
  border-radius: 15px;

  cursor: pointer;

  transition:
    border-color 0.25s ease,
    background 0.25s ease,
    transform 0.25s ease;
}

.cr-checkout__method:hover {
  transform: translateY(-1px);
  background: rgba(255, 255, 255, 0.055);
}

.cr-checkout__method.is-active {
  background:
    linear-gradient(
      135deg,
      rgba(139, 92, 246, 0.12),
      rgba(34, 211, 238, 0.08)
    );

  border-color: rgba(34, 211, 238, 0.55);
}

.cr-checkout__method input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.cr-checkout__method-icon {
  width: 35px;
  height: 35px;
  flex: 0 0 35px;

  display: grid;
  place-items: center;

  color: #c4b5fd;
  background: rgba(139, 92, 246, 0.1);

  border-radius: 11px;
}

.cr-checkout__method-icon svg {
  width: 19px;
  height: 19px;
  stroke-width: 1.7;
}

.cr-checkout__method-text {
  min-width: 0;

  display: flex;
  flex-direction: column;
  gap: 2px;
}

.cr-checkout__method-text strong {
  color: #f8fafc;
  font-size: 12px;
}

.cr-checkout__method-text small {
  color: var(--cr-muted);
  font-size: 10px;
}

.cr-checkout__radio-dot {
  width: 15px;
  height: 15px;
  flex: 0 0 15px;

  margin-left: auto;

  border: 1.5px solid #64748b;
  border-radius: 50%;
}

.cr-checkout__method.is-active
.cr-checkout__radio-dot {
  border: 4px solid var(--cr-cyan);
}

.cr-checkout__card-panel {
  position: relative;
  z-index: 2;
  display: block;
}

.cr-checkout__card-panel.is-hidden {
  display: none;
}

.cr-checkout__field {
  margin-bottom: 14px;
}

.cr-checkout__field label {
  display: block;

  margin-bottom: 7px;

  color: #cbd5e1;

  font-size: 11px;
  font-weight: 650;
}

.cr-checkout__input-wrap {
  position: relative;
}

.cr-checkout__input-wrap input {
  width: 100%;
  height: 45px;

  margin: 0;
  padding: 0 14px;

  color: #f8fafc;
  caret-color: var(--cr-cyan);

  outline: none;

  background: rgba(3, 7, 18, 0.55);

  border: 1px solid rgba(148, 163, 184, 0.16);
  border-radius: 12px;

  font-size: 13px;
}

.cr-checkout__input-wrap input::placeholder {
  color: #526078;
}

.cr-checkout__input-wrap input:focus {
  border-color: rgba(34, 211, 238, 0.65);

  box-shadow:
    0 0 0 3px rgba(34, 211, 238, 0.08);
}

.cr-checkout__field.is-error input {
  border-color: rgba(251, 113, 133, 0.75);
}

.cr-checkout__error {
  display: none;

  margin-top: 5px;

  color: var(--cr-danger);

  font-size: 10px;
}

.cr-checkout__field.is-error
.cr-checkout__error {
  display: block;
}

.cr-checkout__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.cr-checkout__card-mark {
  position: absolute;

  top: 50%;
  right: 13px;

  width: 35px;
  height: 20px;

  transform: translateY(-50%);
}

.cr-checkout__card-mark span {
  position: absolute;
  top: 3px;

  width: 16px;
  height: 16px;

  border-radius: 50%;
}

.cr-checkout__card-mark span:first-child {
  left: 4px;
  background: rgba(139, 92, 246, 0.9);
}

.cr-checkout__card-mark span:last-child {
  right: 4px;
  background: rgba(34, 211, 238, 0.85);
}

.cr-checkout__help {
  position: absolute;

  top: 50%;
  right: 12px;

  width: 19px;
  height: 19px;

  display: grid;
  place-items: center;

  transform: translateY(-50%);

  color: #94a3b8;

  border: 1px solid rgba(148, 163, 184, 0.35);
  border-radius: 50%;

  font-size: 10px;
}

.cr-checkout__wallet {
  position: relative;
  z-index: 2;

  display: none;
  align-items: center;
  gap: 18px;

  margin-bottom: 14px;
  padding: 22px;

  background:
    linear-gradient(
      135deg,
      rgba(124, 58, 237, 0.1),
      rgba(6, 182, 212, 0.06)
    );

  border: 1px solid rgba(148, 163, 184, 0.14);
  border-radius: 16px;
}

.cr-checkout__wallet.is-active {
  display: flex;
}

.cr-checkout__wallet-icon {
  width: 54px;
  height: 54px;
  min-width: 54px;

  display: flex;
  align-items: center;
  justify-content: center;

  background:
    linear-gradient(
      135deg,
      rgba(124, 58, 237, 0.22),
      rgba(6, 182, 212, 0.18)
    );

  border-radius: 14px;
}

.cr-checkout__wallet-icon svg {
  width: 25px;
  height: 25px;

  color: #67e8f9;
  stroke-width: 1.7;
}

.cr-checkout__wallet-content {
  flex: 1;
}

.cr-checkout__wallet-label {
  display: block;

  margin-bottom: 5px;

  color: var(--cr-cyan);

  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.12em;
}

.cr-checkout__wallet-content h3 {
  margin: 0 0 6px;

  color: #f8fafc;

  font-size: 16px;
}

.cr-checkout__wallet-content p {
  margin: 0 0 14px;

  color: var(--cr-muted);

  font-size: 12px;
  line-height: 1.55;
}

.cr-checkout__wallet-account {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;

  padding-top: 12px;

  border-top: 1px solid rgba(148, 163, 184, 0.12);
}

.cr-checkout__wallet-status {
  display: flex;
  align-items: center;
  gap: 7px;

  color: #cbd5e1;

  font-size: 11px;
}

.cr-checkout__wallet-status > span {
  width: 7px;
  height: 7px;

  background: var(--cr-green);
  border-radius: 50%;
}

.cr-checkout__wallet-account strong {
  color: #ffffff;
}

.cr-checkout__form {
  position: relative;
  z-index: 2;
}

.cr-checkout__submit {
  width: 100%;
  height: 48px;

  margin: 3px 0 0;

  display: grid;
  place-items: center;

  color: #ffffff;

  background:
    linear-gradient(
      100deg,
      #7c3aed 0%,
      #8b5cf6 40%,
      #06b6d4 100%
    );

  border: 0;
  border-radius: 13px;

  cursor: pointer;
}

.cr-checkout__submit-default,
.cr-checkout__submit-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;

  font-size: 12px;
  font-weight: 750;
}

.cr-checkout__submit-default svg {
  width: 17px;
  height: 17px;
  stroke-width: 2;
}

.cr-checkout__submit-loading {
  display: none;
}

.cr-checkout__submit.is-loading
.cr-checkout__submit-default {
  display: none;
}

.cr-checkout__submit.is-loading
.cr-checkout__submit-loading {
  display: flex;
}

.cr-checkout__spinner {
  width: 17px;
  height: 17px;

  border: 2px solid rgba(255, 255, 255, 0.3);
  border-top-color: #ffffff;
  border-radius: 50%;

  animation:
    cr-checkout-spin 0.75s linear infinite;
}

.cr-checkout__trust {
  margin-top: 13px;

  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;

  color: #718096;

  font-size: 10px;
}

.cr-checkout__trust svg {
  width: 13px;
  height: 13px;
  stroke-width: 1.8;
}

.cr-checkout__success {
  position: relative;
  z-index: 3;

  min-height: 440px;

  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  text-align: center;
}

.cr-checkout__card.is-success
.cr-checkout__header,
.cr-checkout__card.is-success
.cr-checkout__summary,
.cr-checkout__card.is-success
.cr-checkout__methods,
.cr-checkout__card.is-success
.cr-checkout__card-panel,
.cr-checkout__card.is-success
.cr-checkout__wallet,
.cr-checkout__card.is-success
.cr-checkout__form {
  display: none !important;
}

.cr-checkout__card.is-success
.cr-checkout__success {
  display: flex;
}

.cr-checkout__success-icon {
  width: 78px;
  height: 78px;

  margin-bottom: 20px;

  display: grid;
  place-items: center;

  color: #d1fae5;

  background: rgba(52, 211, 153, 0.12);

  border: 1px solid rgba(52, 211, 153, 0.35);
  border-radius: 50%;
}

.cr-checkout__success-icon svg {
  width: 38px;
  height: 38px;
  stroke-width: 2;
}

.cr-checkout__success-label {
  margin-bottom: 8px;

  color: var(--cr-green);

  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.16em;
}

.cr-checkout__success h3 {
  margin: 0 0 9px;

  color: #ffffff;

  font-size: 27px;
}

.cr-checkout__success p {
  max-width: 330px;
  margin: 0;

  color: var(--cr-muted);

  font-size: 12px;
  line-height: 1.65;
}

.cr-checkout__success-amount {
  width: min(100%, 290px);

  margin-top: 22px;
  padding: 14px 16px;

  display: flex;
  align-items: center;
  justify-content: space-between;

  background: rgba(255, 255, 255, 0.035);

  border: 1px solid rgba(148, 163, 184, 0.12);
  border-radius: 14px;
}

.cr-checkout__success-amount span {
  color: var(--cr-muted);
  font-size: 11px;
}

.cr-checkout__success-amount strong {
  color: #ffffff;
  font-size: 15px;
}

.cr-checkout__reset {
  margin: 16px 0 0;
  padding: 10px 17px;

  color: #c4b5fd;

  background: rgba(139, 92, 246, 0.08);

  border: 1px solid rgba(139, 92, 246, 0.25);
  border-radius: 10px;

  cursor: pointer;

  font-size: 11px;
  font-weight: 700;
}

@keyframes cr-checkout-spin {
  to {
    transform: rotate(360deg);
  }
}

@media (max-width: 560px) {

  .cr-checkout {
    min-height: 580px;
    padding: 18px 12px;
  }

  .cr-checkout__card {
    padding: 20px;
  }

}

@media (max-width: 400px) {

  .cr-checkout__method-grid {
    grid-template-columns: 1fr;
  }

  .cr-checkout__row {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .cr-checkout__secure {
    display: none;
  }

}
JavaScript
const checkout = document.querySelector(".cr-checkout");

if (checkout) {

  const card =
    checkout.querySelector(".cr-checkout__card");

  const cardPanel =
    checkout.querySelector(".cr-checkout__card-panel");

  const walletPanel =
    checkout.querySelector(".cr-checkout__wallet");

  const payButton =
    checkout.querySelector(".cr-checkout__submit");

  const payText =
    checkout.querySelector(".cr-checkout__pay-text");

  const resetButton =
    checkout.querySelector(".cr-checkout__reset");

  const nameInput =
    checkout.querySelector("#cr-card-name");

  const numberInput =
    checkout.querySelector("#cr-card-number");

  const expiryInput =
    checkout.querySelector("#cr-card-expiry");

  const cvcInput =
    checkout.querySelector("#cr-card-cvc");

  const methods =
    checkout.querySelectorAll(".cr-checkout__method");

  const methodRadios =
    checkout.querySelectorAll(
      'input[name="cr-payment-method"]'
    );


  function showError(input) {

    const field =
      input.closest(".cr-checkout__field");

    if (field) {
      field.classList.add("is-error");
    }

  }


  function removeError(input) {

    const field =
      input.closest(".cr-checkout__field");

    if (field) {
      field.classList.remove("is-error");
    }

  }


  function clearErrors() {

    checkout
      .querySelectorAll(".cr-checkout__field")
      .forEach(function (field) {

        field.classList.remove("is-error");

      });

  }


  function getPaymentMethod() {

    const selected =
      checkout.querySelector(
        'input[name="cr-payment-method"]:checked'
      );

    return selected
      ? selected.value
      : "card";

  }


  function updatePaymentMethod() {

    const method =
      getPaymentMethod();

    const isWallet =
      method === "wallet";


    methods.forEach(function (item) {

      const radio =
        item.querySelector(
          'input[type="radio"]'
        );

      if (!radio) return;

      item.classList.toggle(
        "is-active",
        radio.checked
      );

    });


    cardPanel.classList.toggle(
      "is-hidden",
      isWallet
    );


    walletPanel.classList.toggle(
      "is-active",
      isWallet
    );

    walletPanel.setAttribute(
      "aria-hidden",
      isWallet ? "false" : "true"
    );


    if (payText) {

      payText.textContent =
        isWallet
          ? "Pay with Wallet"
          : "Pay $49.00";

    }


    clearErrors();

  }


  methodRadios.forEach(function (radio) {

    radio.addEventListener(
      "change",
      updatePaymentMethod
    );

  });


  nameInput.addEventListener(
    "input",
    function () {

      removeError(this);

    }
  );


  numberInput.addEventListener(
    "input",
    function () {

      let value =
        this.value
          .replace(/\D/g, "")
          .slice(0, 16);

      const groups =
        value.match(/.{1,4}/g);

      this.value =
        groups
          ? groups.join(" ")
          : "";

      removeError(this);

    }
  );


  expiryInput.addEventListener(
    "input",
    function () {

      let value =
        this.value
          .replace(/\D/g, "")
          .slice(0, 4);

      if (value.length > 2) {

        value =
          value.slice(0, 2) +
          "/" +
          value.slice(2);

      }

      this.value = value;

      removeError(this);

    }
  );


  cvcInput.addEventListener(
    "input",
    function () {

      this.value =
        this.value
          .replace(/\D/g, "")
          .slice(0, 4);

      removeError(this);

    }
  );


  function validateCard() {

    let valid = true;

    clearErrors();


    if (
      nameInput.value.trim().length < 2
    ) {

      showError(nameInput);

      valid = false;

    }


    const cardNumber =
      numberInput.value.replace(/\D/g, "");

    if (cardNumber.length !== 16) {

      showError(numberInput);

      valid = false;

    }


    const expiryMatch =
      expiryInput.value.match(
        /^(\d{2})\/(\d{2})$/
      );

    if (!expiryMatch) {

      showError(expiryInput);

      valid = false;

    } else {

      const month =
        Number(expiryMatch[1]);

      const year =
        Number(expiryMatch[2]);

      const now =
        new Date();

      const currentMonth =
        now.getMonth() + 1;

      const currentYear =
        now.getFullYear() % 100;


      if (
        month < 1 ||
        month > 12 ||
        year < currentYear ||
        (
          year === currentYear &&
          month < currentMonth
        )
      ) {

        showError(expiryInput);

        valid = false;

      }

    }


    const cvc =
      cvcInput.value.replace(/\D/g, "");

    if (
      cvc.length < 3 ||
      cvc.length > 4
    ) {

      showError(cvcInput);

      valid = false;

    }


    return valid;

  }


  function processPayment() {

    payButton.classList.add(
      "is-loading"
    );

    payButton.disabled = true;


    setTimeout(function () {

      payButton.classList.remove(
        "is-loading"
      );

      payButton.disabled = false;

      card.classList.add(
        "is-success"
      );

    }, 1800);

  }


  payButton.addEventListener(
    "click",
    function (event) {

      event.preventDefault();


      if (
        payButton.classList.contains(
          "is-loading"
        )
      ) {
        return;
      }


      const method =
        getPaymentMethod();


      if (method === "card") {

        if (!validateCard()) {
          return;
        }

        processPayment();

        return;

      }


      if (method === "wallet") {

        clearErrors();

        processPayment();

      }

    }
  );


  resetButton.addEventListener(
    "click",
    function () {

      nameInput.value = "";
      numberInput.value = "";
      expiryInput.value = "";
      cvcInput.value = "";

      clearErrors();

      card.classList.remove(
        "is-success"
      );

      payButton.classList.remove(
        "is-loading"
      );

      payButton.disabled = false;


      methodRadios.forEach(
        function (radio) {

          radio.checked =
            radio.value === "card";

        }
      );


      updatePaymentMethod();

    }
  );


  updatePaymentMethod();

}

How This Interactive Secure Checkout Works

The Interactive Secure Checkout is a dark payment interface that lets users switch between card and digital wallet payment methods. The HTML keeps the checkout organized into separate areas for the header, order total, payment-method controls, card fields, wallet panel, payment action, and success state. Native radio inputs are used for choosing Card or Wallet, while labels make the complete payment-method cards clickable.

The visual design is built around a 520px maximum-width checkout card on a dark #050816 background. Purple and cyan radial gradients add depth behind the card, while the card itself uses a semi-transparent layered background, a 26px border radius, and a large soft shadow. Several colors are stored as CSS custom properties, including --cr-purple, --cr-cyan, --cr-green, and --cr-danger, making the main palette straightforward to adjust.

Selecting a payment method triggers updatePaymentMethod(). JavaScript reads the checked radio button, updates the is-active class on the selected option, and switches between the card and wallet panels. Choosing Wallet hides the card fields with is-hidden, displays the wallet section with is-active, changes its aria-hidden value, and updates the button text from “Pay $49.00” to “Pay with Wallet.”

The card inputs also include automatic formatting. The card-number listener removes non-numeric characters, limits the value to 16 digits, and groups those digits into sets of four separated by spaces. The expiry field accepts four digits and automatically inserts / after the month. The CVC field strips non-numeric characters and permits a maximum of four digits.

Before a card payment can continue, validateCard() checks each field. The cardholder name must contain at least two characters, the card number must contain exactly 16 digits, and the CVC must contain three or four digits. Expiry validation checks the MM/YY format, verifies that the month is between 1 and 12, and compares the entered month and year with the current date. Invalid fields receive the is-error class, which displays their corresponding error messages and changes the input border.

After successful validation—or immediately when Wallet is selected—processPayment() starts a simulated payment. It adds is-loading to the button, disables it, and shows a CSS spinner. A JavaScript setTimeout() waits 1.8 seconds before applying is-success to the checkout card. CSS then hides the normal checkout sections and displays the payment-complete panel with a .55s entrance animation. This is a front-end demo state rather than an actual payment processor.

The responsive rules also adapt the layout for smaller screens. Below 560px, padding and heading sizes decrease and payment-method descriptions disappear. Below 400px, payment methods and the expiry/CVC fields change to single-column layouts. For more information about the responsive technique used here, see the MDN CSS media queries documentation.

Customizing the Interactive Secure Checkout

Most of the appearance and demo payment details can be changed directly in the HTML and CSS without altering the component structure.

  • Change --cr-bg, --cr-purple, --cr-cyan, --cr-green, and --cr-danger to create a different color scheme.
  • Adjust the checkout card’s 520px maximum width, 26px border radius, or 26px padding.
  • Replace the $49.00 amount in the order summary, payment button, wallet panel, and success amount.
  • Modify the purple-to-cyan gradient used by the payment button and security icon.
  • Change the .25s payment-method transitions or .55s success animation duration.
  • Adjust the 1800 millisecond delay in processPayment() to change how long the demo processing state remains visible.
  • Edit the 560px and 400px media-query breakpoints to control when the compact layouts activate.

Where to Use This Interactive Secure Checkout

This component works best as a front-end checkout concept where payment selection, validation feedback, loading states, and a completion screen need to be demonstrated in one compact interface.

  • Checkout demos for e-commerce interfaces.
  • SaaS subscription payment screens.
  • Digital product purchase pages.
  • UI prototypes for card and wallet payment flows.
  • Front-end portfolios demonstrating form validation and state changes.
  • Payment-interface concepts before integrating a real payment provider.

For another form interface that uses interactive transitions between user states, the 3D Flip Login & Signup Form is a relevant CodeRipple component to explore. For production checkout use, this demo would still need to be connected to a real payment service and appropriate server-side payment handling.

Frequently Asked Questions

Does this checkout process real payments?

No. The current JavaScript simulates processing with a 1.8-second setTimeout() and then displays the success state. It does not send payment information to a payment gateway or server.

How does the card validation work?

JavaScript checks for a cardholder name of at least two characters, exactly 16 card-number digits, a valid MM/YY expiry that has not passed, and a three- or four-digit CVC. Failed checks add an is-error class to the relevant field.

What happens when the Wallet option is selected?

The card input panel is hidden and the digital wallet panel becomes visible. The active payment-method styling changes, aria-hidden is updated on the wallet panel, and the payment button changes to “Pay with Wallet.”

Is the checkout responsive on mobile devices?

Yes. At widths below 560px, the component reduces spacing and hides the smaller payment-method descriptions. Below 400px, both the payment methods and expiry/CVC fields switch from two columns to one.

The Interactive Secure Checkout combines responsive CSS, input formatting, client-side validation, payment-method switching, a loading indicator, and a resettable success state in a single front-end checkout demo.

Scroll to Top