Skip to content
  • No data uploaded
  • Instant results

Tailwind CSS Razorpay Checkout Form for Vanilla JS — Glassmorphism

A production-ready glassmorphism razorpay checkout form: a two-column checkout with an order summary (subtotal, GST, total in INR), contact fields, a UPI / card / netbanking selector and a pay button that opens Razorpay Checkout. Pick your brand color, toggle dark mode and corner radius — the live preview and the Vanilla JS code update instantly in your browser.

Live component editor

Library
Framework
Style
Theme
Corner radius
Live preview
<!-- Requires Tailwind CSS v3 (CLI/PostCSS build, or the Play CDN for prototypes) -->
<div class="w-full max-w-4xl grid grid-cols-1 md:grid-cols-2 gap-6">
  <div>
    <div class="h-full p-6 bg-white/60 backdrop-blur-xl border border-white/60 shadow-2xl rounded-xl">
      <h2 class="text-lg font-semibold text-slate-900">Order summary</h2>
      <div class="mt-4 flex items-start justify-between gap-4">
        <div>
          <p class="font-medium text-slate-900">Pro plan · annual</p>
          <p class="text-sm text-slate-500">Billed once, renews yearly</p>
        </div>
        <p class="font-medium text-slate-900">₹8,474</p>
      </div>
      <div class="mt-6 pt-4 flex flex-col gap-2 text-sm border-t border-slate-200">
        <div class="flex justify-between text-slate-500"><span>Subtotal</span><span>₹8,474</span></div>
        <div class="flex justify-between text-slate-500"><span>GST (18%)</span><span>₹1,525</span></div>
        <div class="flex justify-between text-base font-semibold text-slate-900"><span>Total</span><span>₹9,999</span></div>
      </div>
      <p class="mt-6 text-xs text-slate-500">Secured by Razorpay · PCI DSS compliant</p>
    </div>
  </div>
  <div>
    <form class="h-full p-6 flex flex-col gap-4 bg-white/60 backdrop-blur-xl border border-white/60 shadow-2xl rounded-xl">
      <h2 class="text-lg font-semibold text-slate-900">Payment details</h2>
      <div>
        <label for="rp-email" class="block mb-1.5 text-sm font-medium text-slate-700">Email</label>
        <input id="rp-email" type="email" autocomplete="email" placeholder="you@company.com" class="block w-full px-3 py-2 text-sm rounded-lg border bg-white/70 border-white/80 text-slate-900 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-[#4f46e5] focus:border-[#4f46e5]" required>
      </div>
      <div>
        <label for="rp-phone" class="block mb-1.5 text-sm font-medium text-slate-700">Mobile number</label>
        <input id="rp-phone" type="tel" inputmode="tel" autocomplete="tel" placeholder="+91 98765 43210" class="block w-full px-3 py-2 text-sm rounded-lg border bg-white/70 border-white/80 text-slate-900 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-[#4f46e5] focus:border-[#4f46e5]" required>
      </div>
      <div>
        <p class="block mb-1.5 text-sm font-medium text-slate-700">Payment method</p>
        <div class="flex flex-wrap gap-2" role="group" aria-label="Payment method">
          <button type="button" class="inline-flex items-center justify-center px-3 py-2 text-sm font-semibold rounded-lg border transition-colors border-white/80 bg-white/40 text-slate-700 hover:bg-white/70 aria-pressed:border-[#4f46e5] aria-pressed:text-[#4f46e5] aria-pressed:ring-1 aria-pressed:ring-[#4f46e5]" data-set="method:upi" data-pressed="method:upi" aria-pressed="true">UPI</button>
          <button type="button" class="inline-flex items-center justify-center px-3 py-2 text-sm font-semibold rounded-lg border transition-colors border-white/80 bg-white/40 text-slate-700 hover:bg-white/70 aria-pressed:border-[#4f46e5] aria-pressed:text-[#4f46e5] aria-pressed:ring-1 aria-pressed:ring-[#4f46e5]" data-set="method:card" data-pressed="method:card" aria-pressed="false">Card</button>
          <button type="button" class="inline-flex items-center justify-center px-3 py-2 text-sm font-semibold rounded-lg border transition-colors border-white/80 bg-white/40 text-slate-700 hover:bg-white/70 aria-pressed:border-[#4f46e5] aria-pressed:text-[#4f46e5] aria-pressed:ring-1 aria-pressed:ring-[#4f46e5]" data-set="method:netbanking" data-pressed="method:netbanking" aria-pressed="false">Netbanking</button>
        </div>
        <p class="mt-2 text-xs text-slate-500" data-when="method:upi">Pay with any UPI app — GPay, PhonePe, Paytm or BHIM.</p>
        <p class="mt-2 text-xs text-slate-500" data-when="method:card" hidden>Visa, Mastercard, RuPay and Amex credit or debit cards.</p>
        <p class="mt-2 text-xs text-slate-500" data-when="method:netbanking" hidden>All major Indian banks supported.</p>
      </div>
      <button type="button" class="inline-flex items-center justify-center px-4 py-2.5 text-sm font-semibold rounded-lg bg-[#4f46e5] hover:bg-[#433cc3] text-white shadow-sm transition-colors focus:outline-none focus:ring-2 focus:ring-[#4f46e5] focus:ring-offset-2 focus:ring-offset-white w-full" data-call="payWithRazorpay">Pay ₹9,999</button>
    </form>
  </div>
</div>

<script>
  (() => {
    // Razorpay Standard Checkout — https://razorpay.com/docs/payments/payment-gateway/web-integration/standard/
    const RAZORPAY_KEY_ID = 'rzp_test_YOUR_KEY_ID'; // public key only — the secret stays on your server

    function loadRazorpay() {
      if (window.Razorpay) return Promise.resolve();
      return new Promise((resolve, reject) => {
        const s = document.createElement('script');
        s.src = 'https://checkout.razorpay.com/v1/checkout.js';
        s.onload = resolve;
        s.onerror = () => reject(new Error('Razorpay SDK failed to load'));
        document.head.appendChild(s);
      });
    }

    async function payWithRazorpay() {
      await loadRazorpay();
      // 1) Server creates the order (amount in paise) — never trust a client-side amount.
      const order = await fetch('/api/razorpay/order', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ plan: 'pro-annual' })
      }).then((r) => r.json());
      // 2) Open Checkout for that order.
      const rzp = new window.Razorpay({
        key: RAZORPAY_KEY_ID,
        order_id: order.id,
        amount: order.amount,
        currency: order.currency,
        name: 'Acme Inc.',
        description: 'Pro plan — annual',
        prefill: {
          email: document.getElementById('rp-email')?.value,
          contact: document.getElementById('rp-phone')?.value
        },
        theme: { color: '#4f46e5' },
        // 3) Server verifies razorpay_signature before fulfilling.
        handler: (res) =>
          fetch('/api/razorpay/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(res) })
      });
      rzp.on('payment.failed', (res) => console.error(res.error));
      rzp.open();
    }
    const state = { method: "upi" };
    const actions = { payWithRazorpay };
    const pair = (s) => s.split(':');
    const sync = () => {
      document.querySelectorAll('[data-show]').forEach((el) => (el.hidden = !state[el.dataset.show]));
      document.querySelectorAll('[data-hide]').forEach((el) => (el.hidden = !!state[el.dataset.hide]));
      document.querySelectorAll('[data-when]').forEach((el) => { const [k, v] = pair(el.dataset.when); el.hidden = state[k] !== v; });
      document.querySelectorAll('[data-pressed]').forEach((el) => { const [k, v] = pair(el.dataset.pressed); el.setAttribute('aria-pressed', String(state[k] === v)); });
      document.querySelectorAll('[data-expanded]').forEach((el) => el.setAttribute('aria-expanded', String(!!state[el.dataset.expanded])));
    };
    document.addEventListener('click', (e) => {
      const t = e.target.closest('[data-toggle],[data-open],[data-close],[data-set],[data-call]');
      if (!t) return;
      const { toggle, open, close, set, call } = t.dataset;
      if (call) actions[call]?.(e);
      if (toggle) state[toggle] = !state[toggle];
      if (open) state[open] = true;
      if (close) state[close] = false;
      if (set) { const [k, v] = pair(set); state[k] = v; }
      sync();
    });
    sync();
  })();
</script>
All components →

Free Tailwind CSS Razorpay Checkout Form for Vanilla JS — Glassmorphism by pGento

Install Tailwind CSS for Vanilla JS

Prototype instantly with the Play CDN, or install the Tailwind CLI for production:

<script src="https://cdn.tailwindcss.com"></script>
npm install -D tailwindcss@3
npx tailwindcss init
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch

Add ./**/*.html to content in tailwind.config.js and put the three @tailwind directives in src/input.css.

Use the razorpay checkout form in Vanilla JS

Paste the markup where the component should appear. The small inline <script> wires up the interactive state with one delegated click listener — no framework needed.

Connecting the form to Razorpay

  1. Create an order on your server with the Orders API using your key_secret and return { id, amount, currency } from /api/razorpay/order.
  2. Replace rzp_test_YOUR_KEY_ID with your public key_id (test keys first).
  3. In /api/razorpay/verify, compute HMAC_SHA256(order_id + "|" + payment_id, key_secret) and compare it with razorpay_signature before marking the order paid. Also handle the payment.captured webhook as the source of truth.

The preview never contacts Razorpay — clicking “Pay” there only shows where checkout would open.

Accessibility & customization

Payment methods are toggle buttons with aria-pressed, totals are real text (not images), the phone field uses inputmode="tel" and autocomplete tokens, and the pay button states the exact amount.

Every color, radius and dark-mode choice is baked into plain utility classes, so the copied code has no runtime dependency on this site. The glass style relies on backdrop-filter, supported in all current browsers; place it over a colorful background for the best effect.

Compatibility

ItemDetails
CSS frameworkTailwind CSS v3.4+
LibraryPlain HTML + optional vanilla JS
Interactive statemethod
Dark modeYes — toggle in the editor
StyleGlassmorphism (backdrop blur)

Frequently asked questions

How do I install this Tailwind razorpay checkout form in Vanilla JS?
Create a web page, install Tailwind CSS as shown in the installation section, then paste the generated code.
Can I change the color of the razorpay checkout form?
Yes. Use the brand color picker or type any hex code — the preview and code update instantly, and the color is written directly into the classes you copy.
Does the razorpay checkout form support dark mode?
Yes. Toggle “Dark mode” in the editor to generate a dark palette version of the same component.
Is the razorpay checkout form accessible?
Payment methods are toggle buttons with aria-pressed, totals are real text (not images), the phone field uses inputmode="tel" and autocomplete tokens, and the pay button states the exact amount.
Is this component free for commercial use?
Yes. The generated code is yours to use in personal and commercial projects without attribution.
Tailwind CSS Razorpay Checkout Form for Vanilla JS — Glassmorphism

Embed this tool on your site

Paste this code into any web page. It stays free, fast and ad-free inside your site.

Print or save as PDF

Prints just this tool and its result. Choose “Save as PDF” as the printer to get a file. Branding is stored only in this browser.