@htmlbricks/hb-payment-paypal
v0.76.5
Published
Loads the PayPal JS SDK with your client id and currency, renders PayPal Buttons for a fixed order total, captures payment on approval, and dispatches paymentCompleted when the order is captured successfully.
Readme
hb-payment-paypal — integrator guide
Category: commerce · Tags: commerce, payment · Package: @htmlbricks/hb-payment-paypal
Summary
hb-payment-paypal loads the official PayPal JS SDK using your client id and currency, renders PayPal Buttons for a single fixed order total, and on buyer approval runs order capture (intent: "CAPTURE"). When capture succeeds, the element dispatches a paymentCompleted custom event so your host page can continue checkout, clear a cart, or show a receipt.
The visible PayPal button chrome is drawn by PayPal inside the mounted region; this web component owns wiring, totals, and the completion event.
Custom element tag
<hb-payment-paypal …></hb-payment-paypal>Attributes (HTML / reflected props)
All names are snake_case. Values from HTML are strings; total is coerced with Number(...) inside the component.
| Attribute | Required | Description |
|-----------|----------|-------------|
| paypalid | Yes | PayPal client id (passed to the SDK as client-id). |
| currency | No | EUR or USD (uppercased when set; defaults to EUR). |
| total | No | Order amount (string or number after coercion; default 0 in the implementation). |
| id | No | Optional host id. |
| style | No | Optional on Component; normal host style still applies in the light DOM. |
Behavior
- Script load: On mount and when
paypalid/currency/totalchange, the component callsloadScriptfrom@paypal/paypal-jswithclient-idandcurrency. - Buttons: Renders PayPal Buttons with
layout: "horizontal",tagline: false,height: 40. - Order creation:
createOrderbuilds one purchase unit withintent: "CAPTURE"andamount{ currency_code, value: String(total) }. - Approval:
onApprovecallsactions.order.capture(). On success it dispatchespaymentCompletedwith{ method: "paypal", total }wheretotalis the numeric prop value used for the order (not necessarily re-read from PayPal’s response). - Teardown: On component destroy, it attempts
paypal.Buttons?.().close?.()to release the button instance. - Errors: SDK load or render failures are logged with
console.error; they do not emit a dedicated custom event in the current implementation.
Changing paypalid, currency, or total after load can trigger a remount path (existing buttons are closed before a new load). Ensure your host state stays in sync with the amount shown to the buyer.
Events
Listen with addEventListener or framework bindings on the custom element.
| Event | detail |
|-------|----------|
| paymentCompleted | { method: "paypal"; total: number } |
Use this event as the signal that capture completed on the client; still verify the transaction on your server (webhooks or REST) before fulfilling goods or services.
Styling
The shadow tree forwards Bulma theme setup on :host. PayPal’s iframe still controls the inner button pixels.
CSS custom properties (documented in extra/docs.ts):
| Variable | Role |
|----------|------|
| --bulma-background | Surface behind the PayPal mount region. |
| --bulma-text | Inline copy or labels beside the SDK (if any). |
| --bulma-border | Dividers next to sibling checkout panels. |
| --bulma-radius | Corner radius for Bulma-framed wrappers. |
| --hb-checkout-border | Legacy divider token for composite checkout layouts (defaults to --bulma-border). |
See Bulma CSS variables for how to set --bulma-* on ancestors.
CSS part
| Part | Target |
|------|--------|
| btn | Host wrapper around the PayPal Buttons mount (#paypalbtn). Use ::part(btn) for layout and spacing around the SDK; do not expect to theme PayPal’s internal button art. |
TypeScript typings (authoring)
From types/webcomponent.type.d.ts: Component (paypalid, optional currency, total, id, style) and Events (paymentCompleted).
Integration notes
- Content Security Policy: Allow PayPal’s script and frame origins required by the JS SDK and Smart Payment Buttons, or the load/render step will fail.
- Sandbox vs live: Use a sandbox client id during development and your live client id in production; totals and currency must match what you persist for the order.
- Currencies: Only EUR and USD are handled in the type layer; other codes are not part of the declared
Componentcontract. - Card UI: Older commented markup in
component.wc.sveltereferenced anhb-formcard flow; that path is not active in the shipped template. This component is PayPal-button only today.
Examples
Minimal markup
<hb-payment-paypal
paypalid="YOUR_CLIENT_ID"
currency="EUR"
total="40"
></hb-payment-paypal>With completion handler
<hb-payment-paypal
id="checkout-paypal"
paypalid="YOUR_CLIENT_ID"
currency="USD"
total="12.50"
></hb-payment-paypal>
<script>
const el = document.getElementById("checkout-paypal");
el.addEventListener("paymentCompleted", (e) => {
const { method, total } = e.detail;
console.log("Captured", method, total);
});
</script>Fractional totals
<hb-payment-paypal
paypalid="YOUR_CLIENT_ID"
currency="EUR"
total="1499.99"
></hb-payment-paypal>Related files
| File | Purpose |
|------|---------|
| component.wc.svelte | PayPal SDK load, buttons, capture, event dispatch. |
| types/webcomponent.type.d.ts | Component and Events typings for authors and generated declarations. |
| extra/docs.ts | Catalog metadata, styleSetup (vars / parts), Storybook args, examples. |
