npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@htmlbricks/hb-checkout

v0.76.5

Published

End-to-end checkout flow: editable billing/shipping user profile (`hb-form`), shipment method choice, optional card form, Google Pay (`@google-pay/button-element`), and PayPal via `hb-payment-paypal` according to `gateways` and `payment` JSON. Parses stri

Readme

hb-checkout — checkout

Category: commerce · Tags: commerce, checkout · Package: @htmlbricks/hb-checkout

Summary

hb-checkout is a multi-step commerce checkout surface hosted as a single custom element. It combines:

  • A delivery / identity block (read-only profile, a fixed “display-only” profile mode, or an embedded hb-form for address capture).
  • An optional shipment method block (built from your shipments array into another hb-form radio group, plus read-only summaries with edit affordances).
  • A payment block that can render PayPal (hb-payment-paypal) and/or Google Pay (<google-pay-button> from @google-pay/button-element), driven by a gateways list and a shared payment descriptor.
  • A terms / notice region (default copy + slot), and a post-payment confirmation region when checkout is marked complete.

Structured inputs (shipments, user, gateways, payment) are JSON-serialized strings when used from HTML attributes; the component parses them in an effect and normalizes defaults (for example payment.type defaults to buy if omitted, and Google Pay gateways without cardNetworks get ["VISA","MASTERCARD"]).


Behavior

Data ingestion and normalization

  • payment, shipments, gateways, and user may arrive as strings (JSON). The component parses them inside $effect and replaces the bound values with parsed objects where applicable.
  • If payment.type is missing after parse, it is set to buy.
  • For each Google gateway after parsing gateways, if cardNetworks is missing or empty, it is set to ["VISA","MASTERCARD"].
  • user (when a string) is merged into the internal formUserSchema field value entries so the embedded profile form reflects prefilled data (including nested row / columns ids when present in the schema).

Shipment radio schema

  • The shipment hb-form uses a single required radio field with id shipmentsolution. Its options are rebuilt from shipments: each option’s label is ${label} ${price}${currency} and value is the shipment id.
  • If any shipment has selected: true or standard: true, that shipment’s id becomes the radio value in the schema (so the UI starts on a preselected / standard line when you pass those flags).

Local UI state (not separate custom events)

  • editUser and editShipping toggle between summary rows (with ghost edit buttons) and the hb-form editors.
  • Submitting the profile or shipment form sets internal formUserSchemaSubmitted / formShipmentSchemaSubmitted to yes briefly (with a short timeout back to no) so hb-form can run its submit path while hide_submit="yes" hides the form’s own submit control; the visible Continue button triggers that pulse.
  • completed is a host prop ("yes" | "no"). When a wallet flow finishes successfully, the code sets completed = "yes" locally and fires paymentCompleted. It does not currently dispatch a separate completed custom event (see Events).

Wallet rendering rules

  • PayPal: rendered for every gateway with id === "paypal", passing paypalid, total as a string from payment.total, and listening for hb-payment-paypal paymentCompleted to call the shared paymentCompleted("paypal") handler.
  • Google Pay: rendered only when id === "google" and payment.countryCode is truthy. The <google-pay-button> is configured with environment="TEST" (hardcoded in the template), button-type from payment.type lowercased, button-size-mode="fill", and a paymentRequest built from payment plus gateway fields (gatewayId, gatewayMerchantId, optional merchantId on the gateway, merchantName on payment, allowedCardNetworks from the gateway). loadpaymentdata calls paymentCompleted("google").
  • visibleWalletCount counts gateways that will actually render (PayPal always; Google only with countryCode). The wallet row adds a single-column layout class when that count is 1, and empty PayPal/Google containers are hidden in the single-column case so a non-rendered Google row does not leave a blank grid cell.

Card form

  • A credit-card path exists in libs/formSchemes.ts (formCreditCardSchema) and helper cardChange, but the card UI block is commented out in component.wc.svelte. Consumers should not expect manual card entry in the current build—only PayPal and Google Pay surfaces are active.

Dependencies loaded at runtime

  • addComponent registers @htmlbricks/hb-form and @htmlbricks/hb-payment-paypal at the same version as the builder package.json so nested custom elements resolve consistently.

UI layout (top to bottom)

  1. title slot — Default content is a centered <h1 class="title"> with text Checkout and part="title" (bottom border uses --hb-checkout-border).
  2. #border_top — Main “Delivery” column:
    • Subtitle “Delivery” with send icon; the heading exposes part="subtitle".
    • Profile branch (exact branch is described under Checkout logic):
      • Fixed user mode, read-only filled user, or hb-form + Continue.
    • #shipment_separator (only if shipments.length > 0): shipment summary or hb-form + Continue, depending on user completeness, edit flags, and whether a selected/standard shipment exists.
  3. .payment_title — Separated from the block above by --hb-checkout-border on the top:
    • If completed !== "yes": “Payment Method” subtitle (wallet icon), optional wallet grid, then .footer_note with part="payment_terms_note" wrapping the payment_terms slot.
    • If completed === "yes": payment_completed slot (default centered “payment completed”, total line, text invoice button—no click handler is wired in the default fragment).

Icons use Bootstrap Icons classes; webcomponent.scss imports the icon font into the shadow tree (a <svelte:head> stylesheet link does not apply inside shadow DOM, so the Sass @import is the reliable source).


Checkout logic & visibility

Profile (delivery identity)

| Condition | What you see | | --- | --- | | user?.fixed and not editUser | Minimal read-only area: default userinfo slot content only renders fullName when set (you can replace the slot for richer fixed-profile layouts). | | user.fullName and user.addressWithNumber and not editUser | Read-only Name and Address rows (address concatenates street, city, zip, nationality) plus an edit button → editUser mode. | | Otherwise | “Address” subtitle and hb-form (user schema) + primary Continue. On successful submit → saveUser event, internal user update, editUser cleared. |

Shipment block

Rendered only when shipments is a non-empty array.

  • If ((full profile) fullName + addressWithNumber) or user.fixed) and not editUser:
    • With not editShipping and a selected or standard shipment → read-only fee + arrival rows (arrival formatted with dayjs in this branch) and editeditShipping.
    • Else → shipment hb-form + ContinuesaveShipment selects that id, clears editShipping.
  • Else if not editShipping and a selected or standard shipment exists → read-only shipment summary without requiring the full address branch first (second row shows “Shipping Time” and the raw arriveDate value—not passed through dayjs in this branch; consider keeping ISO strings for consistent display).

Payment block

Wallet buttons render only when all of the following hold:

  • completed !== "yes"
  • Not in editUser and not in editShipping
  • Either no shipments or there is a selected or standard shipment (or the list is treated as satisfied via find on shipments)

Otherwise the payment wallet area is suppressed until the flow is in a “stable” profile + shipment state.


Custom element tag

<hb-checkout></hb-checkout>

Attributes (snake_case; HTML values are strings)

From HTML or setAttribute, pass objects and arrays as JSON strings, numbers as their decimal string, and booleans as yes / no where applicable (see project conventions).

| Attribute | Required | Description | | --- | --- | --- | | shipments | Yes | JSON array of IShipment (see Typings). Each item needs at least price, arriveDate (ISO string recommended), available, id, label, currency. Optional selected, standard preselect a line. | | gateways | Yes | JSON array of IGateway (see Typings). Supports id: paypal | google. PayPal rows need a paypalid. Google rows need gateway configuration fields used in the paymentRequest (gatewayId, gatewayMerchantId, optional merchantId, etc.—see types). | | payment | Yes | JSON IPayment: merchantName, total, currencyCode, countryCode, optional type (IPaymentType; defaults to buy if omitted), optional shipmentFee. countryCode controls whether Google Pay can render. | | user | No | JSON IUser for prefilled / read-only display. Optional fixed: when true (boolean inside the JSON object), the component uses the minimal fixed profile branch. | | completed | No | yes | no (strings). no default. When yes, the component shows the payment_completed slot instead of wallet UI (you can set this from the host after your own backend confirmation, or it flips to yes after paymentCompleted handling in code). | | id | No | Host element id string. |


Events (CustomEvent)

Listeners use the exact event type string (camelCase), e.g. addEventListener("paymentCompleted", …) or in Svelte onpaymentCompleted={…}.

| Event | detail shape | When it fires | | --- | --- | --- | | saveUser | IUser | After the address hb-form submits valid data: fullName, addressWithNumber, city, zip, nationality. Internal schema values and user are updated; editUser becomes false. | | saveShipment | IShipment | After the shipment radio form submits a valid shipmentsolution id that exists in shipments: that shipment is marked selected: true, others selected: false, and editShipping becomes false. | | paymentCompleted | { total: number; method: string; completed: true } | After PayPal or Google Pay signals success via their respective handlers. method is "paypal" or "google". The host completed prop is set to yes (not a separate DOM event). |


Styling

Bulma and host baseline

styles/bulma.scss forwards Bulma 1.x utilities and button, title, plus helpers (spacing, flexbox, gap, typography), then applies light theme + setup on :host. Prefer Bulma CSS variables documented by Bulma and the variables below.

styles/webcomponent.scss pulls in host-baseline shared styles, sets :host display and typography tokens (--bulma-title-size, --bulma-subtitle-size, base font-size from --bulma-size-medium), and defines layout for titles, edit buttons, data rows, the wallet grid, and the terms panel.

CSS custom properties (documented for consumers)

| Variable | Role | | --- | --- | | --bulma-primary | Primary Continue buttons. | | --bulma-link | Ghost terms link color; feeds --edit-color when unset. | | --bulma-text | Default foreground for body and headings inside the flow. | | --bulma-border | Dividers and default border color. | | --bulma-border-weak | Softer border on the terms notice panel. | | --bulma-background | Mixed into the terms notice background (color-mix with border). | | --bulma-text-weak | Muted default terms copy. | | --bulma-title-size, --bulma-subtitle-size, --bulma-subtitle-weight | Title / subtitle scale and weight on :host. | | --bulma-size-medium, --bulma-size-small | Base host font size and smaller terms text. | | --bulma-block-spacing | Line height spacing for definition-style rows. | | --bulma-weight-bold, --bulma-weight-semibold | Edit controls and terms link weight. | | --bulma-radius | Radius for the terms panel and compact links. | | --edit-color | Ghost edit buttons (defaults to --bulma-link). | | --hb-checkout-border | Border under the main title and above the payment section (default 1px solid using --bulma-border). | | --paypal-button-color | Reserved for PayPal chrome overrides (optional). |

Layout classes

  • #payment_btn_container.hb-payment-wallet-row — two-column CSS grid for wallet buttons with gap; collapses to one column with .hb-payment-wallet-row--single when only one wallet is visible.

CSS parts (::part)

Style from outside the shadow tree with hb-checkout::part(...).

| Part | Exposed on | Purpose | | --- | --- | --- | | title | Default heading in title slot | Centered main title; bottom rule uses --hb-checkout-border. | | subtitle | Multiple h3 / h4 subtitles | Section labels (Delivery, Address, Shipment Service, Payment Method, etc.). | | payment_terms_note | Wrapper .footer_note around payment_terms | Panel chrome (border, radius, background mix) for legal / policy copy. |


Slots

| Slot | Default | Purpose | | --- | --- | --- | | title | <h1 part="title">Checkout</h1> | Replace or wrap the main title region. | | userinfo | Conditional name row in fixed user mode | Extra markup in the billing / shipping profile area around hb-form / read-only rows when you need custom layout (especially with user.fixed). | | payment_terms | Short default sentence + ghost terms and conditions button (no navigation wired) | Replace with binding legal text, links, or checkboxes. Still wrapped by payment_terms_note styling unless you override via ::part. | | payment_completed | Centered confirmation title, total, invoice text button | Replace the post-payment panel when completed="yes". |


Typings

Authoring types live in types/webcomponent.type.d.ts. Shapes below mirror that file.

export type IShipment = {
  price: number;
  selected?: boolean;
  standard?: boolean;
  arriveDate: Date;
  available: boolean;
  id: string;
  label: string;
  currency: string;
};

export type IUser = {
  fullName: string;
  addressWithNumber?: string;
  city?: string;
  zip?: string;
  nationality?: string;
  fixed?: boolean;
};

export type IGateway = {
  id: "google" | "paypal";
  label: string;
  fixedPrice?: number;
  currency?: "€" | "$";
  percentagePrice?: number;
  paypalid?: string;
  cardNetworks?: string[];
  gatewayId?: string;
  gatewayMerchantId?: string;
  merchantId?: string;
};

export type IPaymentType =
  | "book"
  | "buy"
  | "checkout"
  | "donate"
  | "order"
  | "pay"
  | "plain"
  | "subscribe";

export type IPayment = {
  merchantName: string;
  total: number;
  currencyCode: string;
  countryCode: string;
  type?: IPaymentType;
  shipmentFee?: number;
};

export type Component = {
  id?: string;
  shipments: IShipment[];
  user?: IUser;
  gateways: IGateway[];
  payment: IPayment;
  completed?: "yes" | "no";
};

export type Events = {
  paymentCompleted: { total: number; method: string; completed: true };
  saveUser: IUser;
  saveShipment: IShipment;
};

Runtime vs authoring: At runtime, JSON parsing yields plain objects; date fields may be strings until you convert them—dayjs is used only in one shipment summary branch.


Examples

PayPal only (minimal host page)

<hb-checkout
  completed="no"
  payment='{"merchantName":"Acme","total":"49.99","currencyCode":"EUR","countryCode":"IT","type":"buy"}'
  shipments='[{"id":"std","label":"Standard","price":5,"arriveDate":"2026-04-01T00:00:00.000Z","available":true,"currency":"€","standard":true}]'
  gateways='[{"id":"paypal","label":"PayPal","paypalid":"YOUR_CLIENT_OR_SANDBOX_ID"}]'
></hb-checkout>

PayPal + Google Pay (Google requires countryCode and gateway fields)

<hb-checkout
  completed="no"
  payment='{"merchantName":"Acme","total":"99.00","currencyCode":"EUR","countryCode":"IT","type":"buy"}'
  shipments='[{"id":"express","label":"Express","price":"9","arriveDate":"2026-04-18T12:00:00.000Z","available":true,"currency":"€"}]'
  gateways='[
    {"id":"paypal","label":"PayPal","paypalid":"YOUR_PAYPAL_ID"},
    {
      "id":"google",
      "label":"Google Pay",
      "gatewayId":"example",
      "gatewayMerchantId":"exampleGatewayMerchantId",
      "merchantId":"01234567890123456789",
      "cardNetworks":["VISA","MASTERCARD"]
    }
  ]'
></hb-checkout>

Prefilled profile (read-only until edit)

<hb-checkout
  completed="no"
  payment='{"merchantName":"Acme","total":"45","currencyCode":"EUR","countryCode":"IT"}'
  shipments='[{"id":"s1","label":"Ground","price":10,"arriveDate":"2026-05-01T08:00:00.000Z","available":true,"currency":"€","selected":true}]'
  gateways='[{"id":"paypal","label":"PayPal","paypalid":"sandbox"}]'
  user='{"fullName":"Jane Example","addressWithNumber":"Via Roma 1","city":"Milan","zip":"20100","nationality":"IT"}'
></hb-checkout>

Completed state (confirmation slot default)

<hb-checkout
  completed="yes"
  payment='{"merchantName":"Acme","total":"45","currencyCode":"EUR","countryCode":"IT"}'
  shipments='[]'
  gateways='[]'
></hb-checkout>

Listening from JavaScript

const el = document.querySelector("hb-checkout");
el.addEventListener("saveUser", (e) => console.log("user", e.detail));
el.addEventListener("saveShipment", (e) => console.log("shipment", e.detail));
el.addEventListener("paymentCompleted", (e) =>
  console.log(e.detail.method, e.detail.total, e.detail.completed),
);

Operational notes

  • Google Pay is wired with environment="TEST" in the template; change the source before production if you need PRODUCTION.
  • Nested hb-form and hb-payment-paypal carry their own styles and events—consult their READMEs for schema knobs and PayPal props.
  • This component declares no i18n language list in extra/docs.ts; UI strings are English in the template.
  • Bundle size: pulling hb-checkout also implies hb-form (large input surface) and hb-payment-paypal per componentSetup.dependencies in extra/docs.ts.