MPUI-KIT

Payment method picker

Selectable cards for Mobile Money operators, card and cash. Choosing a Mobile Money option reveals a phone input for that operator right under the cards.

Preview

Moyen de paiement
methodId
null
e164
null
ready
false

Installation

npx shadcn@latest add @mpui-kit/payment-method-picker

Requires the @mpui-kit namespace. See Getting started.

Usage

import { PaymentMethodPicker } from "@/components/mpui-kit/payment-method-picker"
import { emptySelection, type PaymentSelection } from "@/lib/mpui-kit/payment-methods"

// Inside <MpuiKitProvider country={cm}>
const [selection, setSelection] = useState<PaymentSelection>(emptySelection)
const [ready, setReady] = useState(false)

<PaymentMethodPicker
  value={selection}
  onChange={(next, resolved) => {
    setSelection(next)
    setReady(resolved.ready)          // card and cash: true. Mobile Money: needs a valid number
    console.log(resolved.e164)        // "+237651234567" for Mobile Money once valid
  }}
/>

Props

Props
PropTypeDefaultDescription
valuePaymentSelection—The current choice: { methodId: string | null, phone: string }. phone is the national number as digits. Makes the picker controlled.
defaultValuePaymentSelectionnothing selectedInitial choice for an uncontrolled picker.
onChange(selection: PaymentSelection, resolved: ResolvedPayment) => void—Called when the method or the phone number changes. resolved.ready says whether the selection can be paid, and resolved.e164 is the number for Mobile Money.
methodsPaymentMethod[]defaultPaymentMethods(country)Methods to offer. By default: Mobile Money for each operator with a wallet, then card and cash.
countryCountryConfigMpuiKitProvider's countryCountry to use. Throws if neither this nor a provider is set.
locale"fr" | "en"MpuiKitProvider's locale, then “fr”Language of the labels and messages.
legendstring“Payment method”Group label read by screen readers.
errorstring—Error under the cards, for example “Choose a payment method to continue.”
operatorLogosRecord<string, ReactNode>—Your own logos by operator id, shown instead of the color dot.
disabledbooleanfalseDisables every card and the phone field.
phoneErrorstring—Error for the phone field of the chosen Mobile Money method. Overrides its built-in error.
classNames{ legend, options, option, optionLabel, optionDescription, phone, error }—Class names for parts of the picker. Style the selected card with has-[:checked]:... in option. Each part also has a data-slot attribute.
...propsComponentProps<'fieldset'>—Other fieldset props, such as className.

Choosing the methods

A country offers Mobile Money for every operator that has a wallet in its data. Pass methods to change that.

import { defaultPaymentMethods } from "@/lib/mpui-kit/payment-methods"

// Mobile Money only
<PaymentMethodPicker methods={defaultPaymentMethods(cm, { card: false, cash: false })} />

// Your own list
<PaymentMethodPicker
  methods={[
    { id: "mtn", kind: "mobile_money", operatorId: "mtn" },
    { id: "cash", kind: "cash", label: "Pay on arrival", description: "No fees" },
  ]}
/>

Notes

  • Native radios. The cards are radio inputs in a labelled fieldset, so arrow keys move the choice, the group is one tab stop, and screen readers announce it as a group. There is no custom key handling to break.
  • Focus is not moved when the phone field appears, because that would interrupt arrow-key navigation between cards. The field sits right under the cards.
  • The phone number is kept when you switch between Mobile Money operators, in case someone picked the wrong one.
  • A number that belongs to a different known operator is rejected (operator_mismatch). A prefix that is not in the country data is accepted, because the data is community-maintained and may be incomplete.
  • This component only collects a choice. It never calls a payment API. See the checkout block for the full flow.