← All Open Collective pages

The Razorpay row on the payment step

This is the one screen where an Indian donor hands over money. Today the row that takes that money is drawn as a bank.

What is wrong: Razorpay renders with a solid bank-building icon, directly above a row called Bank transfer that carries an outline bank-building icon. Two rows, the same picture, opposite meanings. The label — Razorpay (Cards, UPI & more) — leads with a company name most donors do not choose by, and buries the word they are looking for.

What I recommend: lead with the method, not the processor. Title UPI, cards & netbanking; a quiet rupee icon; and Razorpay named in the subtitle where it does its real job, which is telling the donor who handles their card details.

What I am not recommending: the Razorpay logo. Reasons below — they are about this list's own grammar, not about squeamishness.

Today

Rendered at the two widths that matter: a phone column and the desktop card. The worst case is a host that has Stripe, PayPal, Razorpay and bank transfer all switched on.

Today — phone (335px)
New credit/debit card
PayPal
Razorpay (Cards, UPI & more)
Bank transferInstructions to complete payment will be given on the next page.
The third and fourth rows carry the same building. One is a payment aggregator, the other is a manual NEFT transfer you finish somewhere else.
Measured, in the browser
RowIcon boxWeight
New credit/debit card26 × 18grey fill
PayPal21 × 24grey fill
Razorpay26 × 26solid black
Bank transfer20 × 20outline

The Razorpay icon is the largest and heaviest thing in the column. Not a styling choice — getPaymentMethodIcon is called without a size, so the SVG has no width or height attributes and fills the 26px slot. Every other row passes a size.

Recommended

Recommended — phone (335px)
UPI, cards & netbankingHandled by Razorpay — Aikyam India never sees your card details.
Bank transferInstructions to complete payment will be given on the next page.
Icon 20 × 20, the same box and stroke weight as the row below it. Nothing in the column shouts.
Recommended — desktop card (566px)
UPI, cards & netbankingHandled by Razorpay — Aikyam India never sees your card details.
Bank transferInstructions to complete payment will be given on the next page.
The subtitle wraps to two lines on a phone and one on desktop. Row height goes 59px → 89px on a phone, which is what the bank-transfer row already costs.

Why the label reads this way

Why not the Razorpay logo

Icons I tried and rejected

The change

Two files. Everything is additive or in-place; no component is restructured.

1. lib/payment-method-utils.js — stop drawing a bank

import React from 'react';
import { Bank } from '@styled-icons/boxicons-solid/Bank';
+import { IndianRupee } from 'lucide-react';
…
  } else if (service === PAYMENT_METHOD_SERVICE.RAZORPAY) {
-    // No dedicated icon yet — Razorpay is a card/UPI aggregator, a bank icon reads closer
-    // than a generic credit card would.
-    return <Bank size={size} />;
+    // Deliberately not a bank: the manual bank-transfer row already uses a Landmark icon,
+    // and Razorpay is UPI-first. Deliberately not the Razorpay mark either — this list
+    // de-brands (see the grey PayPal icon). ₹ is the one claim that is always true here.
+    return <IndianRupee size={size || 20} className="h-5 w-5" />;
  } else if (type === PAYMENT_METHOD_TYPE.PREPAID) {

lucide-react is already a dependency and is what the manual payment providers in this same list use (Landmark, HandCoins). No new package.

2. components/contribution-flow/utils.js — the words

    // Razorpay
    if (hostHasRazorpay && !disabledPaymentMethodTypes?.includes(PAYMENT_METHOD_TYPE.PAYMENT)) {
      uniquePMs.push({
        key: 'razorpay',
-        title: 'Razorpay (Cards, UPI & more)',
+        title: (
+          <FormattedMessage
+            id="ContributePayment.razorpay"
+            defaultMessage="UPI, cards & netbanking"
+          />
+        ),
+        subtitle: (
+          <FormattedMessage
+            id="ContributePayment.razorpaySubtitle"
+            defaultMessage="Handled by Razorpay — {collective} never sees your card details."
+            values={{ collective: collective.name }}
+          />
+        ),
        paymentMethod: {
          service: PAYMENT_METHOD_SERVICE.RAZORPAY,

FormattedMessage is already imported in this file, and subtitle is already rendered by PaymentMethodList.tsx (the manual providers use it). Confirm the in-scope variable holding the collective before wiring {collective} — if it is awkward, drop the variable and use “Handled by Razorpay. Your card details are never shared with us.”

Also wrong on this step, for an Indian donor

Two things I saw that are somebody else's call

What I could not check