Zoeken...  ⌘K GitHub

FormPayment Forms

Betaalformulier met methode-keuze (iDEAL/creditcard/SEPA), kaartvelden en ordersamenvatting.

/form-payment
src/components/forms/FormPayment.astro
---
/**
 * FormPayment — betaalformulier met methode-keuze (iDEAL/creditcard/SEPA),
 * kaartvelden en een ordersamenvatting bovenaan. Velden zijn visueel (demo).
 *
 * Props:
 * - summaryLabel?: string
 * - amount?: string
 * - summaryDesc?: string
 * - heading?: string
 * - methods?: { value: string; label: string }[]
 * - securityNote?: string
 * - submitLabel?: string
 */
interface Props {
  summaryLabel?: string;
  amount?: string;
  summaryDesc?: string;
  heading?: string;
  methods?: { value: string; label: string }[];
  securityNote?: string;
  submitLabel?: string;
}
const {
  summaryLabel = 'Totaal te betalen',
  amount = '€ 750 / maand',
  summaryDesc = 'Growth pakket, maand 1',
  heading = 'Betalingsgegevens',
  methods = [
    { value: 'ideal', label: 'iDEAL' },
    { value: 'card', label: 'Creditcard' },
    { value: 'sepa', label: 'SEPA Bankoverschrijving' },
  ],
  securityNote = 'Betalingen worden verwerkt via een beveiligde SSL-verbinding',
  submitLabel = 'Betaling bevestigen',
} = Astro.props;
---

<section class="bl-section fpm">
  <div class="bl-inner fpm-inner">
    <div class="fpm-card">
      <div class="fpm-order-summary">
        <div class="fpm-order-label">{summaryLabel}</div>
        <div class="fpm-order-amount">{amount}</div>
        <div class="fpm-order-desc">{summaryDesc}</div>
      </div>
      <h2 class="fpm-heading">{heading}</h2>
      <form class="fpm-form" novalidate aria-label="Betalingsformulier (demo)">
        <div class="fpm-methods" role="group" aria-label="Betaalmethode">
          {methods.map((m, i) => (
            <label class="fpm-method">
              <input class="fpm-method-input" type="radio" name="payment_method" value={m.value} checked={i === 0} />
              <span class="fpm-method-box">{m.label}</span>
            </label>
          ))}
        </div>
        <div class="fpm-card-fields">
          <div class="fpm-field">
            <label class="fpm-label" for="fpm-holder">Naam kaarthouder</label>
            <input class="fpm-input" type="text" id="fpm-holder" name="card_holder" placeholder="Naam kaarthouder" autocomplete="cc-name" />
          </div>
          <div class="fpm-field">
            <label class="fpm-label" for="fpm-number">Kaartnummer</label>
            <input class="fpm-input fpm-input--card" type="text" id="fpm-number" name="card_number" placeholder="1234 5678 9012 3456" maxlength="19" autocomplete="cc-number" inputmode="numeric" />
          </div>
          <div class="fpm-row">
            <div class="fpm-field">
              <label class="fpm-label" for="fpm-expiry">Vervaldatum</label>
              <input class="fpm-input" type="text" id="fpm-expiry" name="expiry" placeholder="MM / JJ" maxlength="7" autocomplete="cc-exp" inputmode="numeric" />
            </div>
            <div class="fpm-field">
              <label class="fpm-label" for="fpm-cvv">CVV<span class="fpm-tooltip" title="3-cijferige code op de achterkant van je kaart">?</span></label>
              <input class="fpm-input" type="text" id="fpm-cvv" name="cvv" placeholder="•••" maxlength="4" autocomplete="cc-csc" inputmode="numeric" />
            </div>
          </div>
        </div>
        <div class="fpm-security">
          <span class="fpm-security-icon" aria-hidden="true">→</span>
          <span>{securityNote}</span>
        </div>
        <button class="fpm-submit" type="submit">{submitLabel}</button>
      </form>
    </div>
  </div>
</section>

<style>
.fpm-inner{display:flex;justify-content:center}
.fpm-card{width:100%;max-width:520px}
.fpm-order-summary{background:var(--color-primary, #0a0a0a);color:#fff;padding:1.5rem;border-radius:12px;margin-bottom:2rem;text-align:center}
.fpm-order-label{font-size:.8rem;color:#aaa;text-transform:uppercase;letter-spacing:.1em;margin-bottom:.25rem}
.fpm-order-amount{font-size:2rem;font-weight:800;margin-bottom:.25rem}
.fpm-order-desc{font-size:1rem;color:#e8e8e8}
.fpm-heading{font-size:1.4rem;font-weight:800;color:var(--color-primary, #0a0a0a);margin:0 0 1.5rem}
.fpm-form{display:flex;flex-direction:column;gap:1.25rem}
.fpm-methods{display:flex;gap:.75rem;flex-wrap:wrap}
.fpm-method{cursor:pointer;flex:1;min-width:120px}
.fpm-method-input{display:none}
.fpm-method-box{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.75rem;background:#f5f5f5;border:1.5px solid transparent;border-radius:8px;font-size:1rem;font-weight:500;color:#374151;transition:border-color .15s,background-color .15s,color .15s}
.fpm-method-input:checked+.fpm-method-box{border-color:var(--color-accent, #6366f1);background:#eef2ff;color:var(--color-accent, #6366f1);font-weight:600}
.fpm-card-fields{display:flex;flex-direction:column;gap:1rem;background:#f9f9f9;padding:1.25rem;border-radius:10px}
.fpm-row{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
.fpm-field{display:flex;flex-direction:column;gap:.35rem}
.fpm-label{font-size:.95rem;font-weight:600;color:var(--color-primary, #0a0a0a);display:flex;align-items:center;gap:.35rem}
.fpm-tooltip{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;background:#ddd;color:#555;font-size:.7rem;font-weight:700;cursor:help}
.fpm-input{padding:.7rem .9rem;border:1.5px solid #ddd;border-radius:8px;font-size:1rem;color:var(--color-primary, #0a0a0a);background:#fff;transition:border-color .2s;font-family:inherit;box-sizing:border-box;width:100%}
.fpm-input:focus{outline:none;border-color:var(--color-accent, #6366f1);box-shadow:0 0 0 3px #6366f11f}
.fpm-security{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:#555}
.fpm-security-icon{font-size:1rem}
.fpm-submit{padding:.95rem;background:var(--color-accent, #6366f1);color:#fff;border:none;border-radius:8px;font-size:1rem;font-weight:600;cursor:pointer;transition:opacity .2s}
.fpm-submit:hover{opacity:.88}
</style>

Props

Prop Type Default Beschrijving
summaryLabel string 'Totaal te betalen' Label boven het bedrag
amount string - Te betalen bedrag
summaryDesc string - Omschrijving onder het bedrag
heading string 'Betalingsgegevens' Kop boven het formulier
methods { value: string; label: string }[] - Betaalmethoden; eerste staat standaard aan
securityNote string - Beveiligingsmelding onderaan
submitLabel string 'Betaling bevestigen' Tekst op de submit-knop

* = verplicht