@givinglite/react
v0.4.6
Published
Native React donation form for GivingLite card and Canadian PAD donations
Readme
@givinglite/react
Native React form for one-time credit card and Canadian PAD donations through GivingLite. It renders in the host DOM and is designed for a Next.js App Router client component. Stripe.js owns the secure card fields, bank-account authorization, and mandate frames; the SDK never collects, receives, or stores payment details.
Pilot release: Versions below 1.0 are intended for controlled GivingLite pilots. The package supports one-time credit card and Canadian PAD donations in Stripe live and test modes, requires a configured GivingLite backend, and may introduce breaking API changes between minor releases.
Install
npm install @givinglite/reactReact 18 and React 19 are supported as peer dependencies.
For an end-to-end charity-site implementation runbook, including local package linking and provider migration, see the GivingLite React SDK integration guide.
Next.js App Router
Create a client component. Do not put a private API credential in this component; apiUrl is a public browser-visible GivingLite origin.
'use client';
import { GivingLiteDonationForm } from '@givinglite/react';
export function DonationForm() {
return (
<GivingLiteDonationForm
apiUrl="https://api.givinglite.example"
charitySlug="example-charity"
formSlug="general"
branding={{ accentColor: '#155e75', accentTextColor: '#ffffff' }}
copy={{ title: 'Support our work' }}
onStarted={({ idempotencyKey }) =>
console.info('Started', idempotencyKey)
}
onComplete={({ status }) => console.info('Complete', status)}
onError={(error) => console.error(error)}
/>
);
}apiUrl, charitySlug, and formSlug are the only required props. The optional testMode boolean defaults to false, so omitted configuration uses Stripe live mode and can collect real payments. Set testMode to true explicitly in development and test environments; the form then displays a test-mode notice.
The SDK automatically loads the published form configuration, including payment methods, suggested and default amounts, minimum amount, custom-amount and cost-coverage policy, charity identity, form copy, and branding. The form shows a loading or error state without donation controls until that authoritative configuration is available.
The optional branding and copy props are presentation-only overlays. They can adjust host-site wording and safe six-digit hex accent colors, but cannot override donation policy. When no accent is supplied, the SDK uses the charity's primary color and derives readable button text. stripeLoader, fetcher, and lifecycle callbacks remain injectable.
All monetary values are integer Canadian cents. Styles are included in the rendered component, use glr-pad-prefixed selectors, and do not require Tailwind or host CSS. The API must permit CORS requests from the host site.
API contract
The SDK first sends GET {apiUrl}/api/v1/charities/{charitySlug}/forms/{formSlug}/configuration. Test mode adds ?test_mode=1; live mode omits the query parameter. The configuration response must echo testMode. The SDK then sends POST {apiUrl}/api/v1/charities/{charitySlug}/forms/{formSlug}/donations with an Idempotency-Key UUID header and this JSON body:
{
"amount": 5000,
"donor": {
"firstName": "Ada",
"lastName": "Lovelace",
"email": "[email protected]",
"marketingConsent": true,
"address": {
"line1": "123 Main Street",
"line2": "Unit 4",
"city": "Toronto",
"state": "ON",
"postal_code": "M5V 2T6",
"country": "CA"
}
},
"campaignId": null,
"coverCosts": true,
"paymentMethod": "card",
"testMode": false
}paymentMethod is card or acss_debit. Card selection advances to an inline Stripe Payment Element with Stripe Link disabled, while PAD opens Stripe's secure Canadian bank authorization. amount is the base gift in integer cents. The response must contain matching paymentMethod and testMode values, clientSecret, publishableKey, and either a same-origin signed statusUrl or reconciliationUrl. Before loading Stripe.js, the SDK rejects a publishable key whose pk_test_ or pk_live_ prefix does not match the requested mode. After Stripe returns a PaymentIntent, the SDK posts to that signed URL without supplying a Stripe identifier; GivingLite reconciles the PaymentIntent already stored for the attempt. The reconciliation response may return stripeStatus, status, or paymentStatus; the Stripe-specific value takes precedence so verification requirements are not hidden by a coarse pending state. Supported results are processing/pending, verification required, succeeded/paid/completed, and failed/canceled/requires payment method. Unknown Stripe statuses are conservatively displayed as processing because PAD settlement is asynchronous.
The first step collects the donation amount, payment method, and optional processing-cost coverage. Coverage follows Stripe nonprofit rates — cards 2.2% + $0.30, bank PAD 1% + $0.40 capped at $5 — and updates when the payment method changes. The second step collects first and last name, then email address, followed by optional marketing consent. The third step collects the billing address before payment begins. The SDK sends the address to GivingLite and to Stripe as payment_method.billing_details.address (under payment_method_data for card confirmation). Country is an ISO two-letter code. Street, city, and country are required; province/state and postal/ZIP code are also required for Canada and the US. Unit is optional. GivingLite initializes a new donor profile from these fields, but an unauthenticated donation attempt cannot overwrite an existing donor's profile. Address changes participate in request idempotency checks. Deploy the donor-address migration before using the updated SDK.
The Province field is a required dropdown for Canada (all provinces and territories) and switches to a required State dropdown for the United States (50 states and Washington, DC). Options display full names and submit standard two-letter codes, such as ON, QC, NY, or CA, to GivingLite and Stripe. Other countries use an optional free-text Province field. Changing the country clears the Province/State value to prevent carrying a region into the wrong country.
Receipt preference applies to monthly donations, so this one-time donation form does not collect or send it. One-time donations do not inherit a donor's saved receipt preference or include it in Stripe metadata. The API still accepts valid preferences from older embeds for retry compatibility, but does not save them on new donations or donor profiles. The exported createDonationRequest helper retains its legacy receipt-preference argument position but ignores its value.
Marketing consent is optional and defaults to unchecked. The SDK sends an explicit donor.marketingConsent boolean. GivingLite snapshots the choice on the donation and initializes it for a new donor profile; an unauthenticated attempt cannot overwrite an existing donor's consent. Older clients may omit it. Consent changes participate in idempotency checks and are not sent to Stripe metadata.
The server remains authoritative for charity/form availability, amount, cost coverage, PaymentIntent metadata, and final payment status. A browser callback is not proof of settlement.
Attribution
The native React form captures attribution once when it mounts on the charity page. It sends the URL's nonempty utm_* query parameters (including source, medium, campaign, id, term, content, source_platform, creative_format, marketing_tactic, and custom UTM parameters), document.referrer as referrer, and the current page as page_url in an optional attribution request object. GivingLite snapshots these values on the donation and includes them as flat Stripe PaymentIntent metadata; Stripe copies that metadata to the Charge when it is created.
URL fields exclude credentials, query strings, and fragments. UTM values are decoded and trimmed. Capture is limited to 20 UTM keys, lowercase names up to 40 characters, and 500 characters per value to respect Stripe metadata limits. Non-UTM query parameters are not collected. Attribution is untrusted reporting data and cannot override source, campaign selection, or charity tenancy.
There are no cookies or cross-page attribution storage. UTMs must be present on the page when the form mounts. Referrer availability depends on the browser and referring site's policy; direct visits may have none. Attribution does not automatically cover the separate hosted/iframe Checkout flow or recurring renewals. Never put sensitive donor information into UTM values.
Content Security Policy
Stripe.js is loaded directly from https://js.stripe.com/v3/; it is not bundled or proxied. At minimum, account for these sources in the host CSP, along with the configured GivingLite API origin:
script-src https://js.stripe.com
frame-src https://js.stripe.com https://hooks.stripe.com
connect-src https://api.stripe.com https://api.givinglite.exampleMerge those origins into the site's existing policy rather than replacing it. Stripe may require additional regional/payment-method origins; follow Stripe's current CSP documentation. Stripe still uses its own secure fields and frames to collect card or bank details and mandate acceptance.
Testing
stripeLoader and fetcher can be injected for component integration tests. Pure URL, configuration, request, color, and status helpers are exported for unit testing. Importing the package is SSR-safe, while rendering and Stripe confirmation must happen in a client component.
The package currently keeps its test runtime dependency-free, so configuration-fetch lifecycle behavior does not have an automated DOM test. Manually verify loading, failed configuration, identity changes, hidden custom amounts, and cost-coverage defaults when integrating the component in a browser.
