Detent web components
By Shane Logsdon

Commerce & auth

Payment Status

Implemented

Refined transaction status card with self-drawing checkmark and receipt actions

detent-payment-status

Port status
Catalog status
implemented
Origin
upstream
Phase
3
Wave
phase-3-data
Group
Commerce & auth

8.0 KB gzip for the class module

Variants

Sample data; nothing is fetched or sent. The success card reveals the transaction metadata, the itemized receipt and the copy button; the failed card shows the non-aggressive recovery actions. View Receipt emits one composed event per toggle and Download only emits detent-download-receipt — the component never starts a download, so the demo logs receiptText instead. Both cards announce the status change through a visually hidden live region, so success and failure are readable without colour.

Recorded states

  • error recorded state; no setter
  • reduced motion recorded state; no setter
  • processing recorded state; no setter
  • verifying recorded state; no setter
  • success recorded state; no setter
  • failed recorded state; no setter
  • refunded recorded state; no setter

Usage

Import

import '/components/payment-status/define.js';

// or register it yourself
import { DetentPaymentStatus } from '/components/payment-status/payment-status.js';

Attributes

  • amount
  • currency
  • date
  • error-message
  • last4
  • merchant-name
  • payment-method
  • refund-reason
  • status
  • transaction-id

Properties

  • items
  • onChangePaymentMethod
  • onDownloadReceipt
  • onRetry
  • onViewReceipt

Slots

No slots are recorded for this component.

Events

  • detent-retry — {}
  • detent-change-payment-method — {}
  • detent-download-receipt — {}
  • detent-view-receipt — {}

Example

Runnable example: site/examples/payment-status.ts. The snippet below is generated from the catalogued attributes.

<detent-payment-status
  amount="$149.00"
  currency="{{MAIN}}quot;
  date="Today at 3:42 PM"
  error-message
  last4="4242"
  merchant-name="Detent Cloud"
  payment-method="Apple Pay"
  refund-reason
  status="processing"
  transaction-id="tx_9842a8d11c7f"
></detent-payment-status>

Property-only values

const element = document.querySelector('detent-payment-status');
if (element !== null) {
  // items: PaymentReceiptItem[]
  element.items = [];
  // onRetry: () => void
  element.onRetry = () => {};
  // onChangePaymentMethod: () => void
  element.onChangePaymentMethod = () => {};
}

Source

The pinned upstream source for this row:

  • src/components/ui/PaymentStatus.tsx sha256 e8284c0343ad…

Native files

The native module and its artifacts:

  • src/components/payment-status/payment-status.ts
  • src/components/payment-status/styles.css
  • src/components/payment-status/define.ts
  • docs/components/payment-status.md
  • site/examples/payment-status.ts
  • tests/browser/payment-status.spec.ts
  • evidence/components/payment-status.md

API

Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.

Attributes

Attributes
AttributePropertyTypeDefaultNotes
amountamountstring | number'$149.00'Kebab-case attribute; camelCase property.
currencycurrencystring'{{MAIN}}#39;Kebab-case attribute; camelCase property.
datedatestring | Date'Today at 3:42 PM'Kebab-case attribute; camelCase property.
error-message———Recorded in the catalog as an attribute.
last4last4string'4242'Kebab-case attribute; camelCase property.
merchant-namemerchantNamestring'Detent Cloud'Kebab-case attribute; camelCase property.
payment-methodpaymentMethodstring'Apple Pay'Kebab-case attribute; camelCase property.
refund-reason———Recorded in the catalog as an attribute.
statusstatus'processing' | 'verifying' | 'success' | 'failed' | 'refunded''processing'Kebab-case attribute; camelCase property.
transaction-idtransactionIdstring'tx_9842a8d11c7f'Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
itemsPaymentReceiptItem[][...]Property-only: assign from script; not accepted as an attribute.
onChangePaymentMethod() => voidundefinedProperty-only: assign from script; not accepted as an attribute.
onDownloadReceipt——Recorded in the catalog without a top-level type; pinned from source when the row is ported.
onRetry() => voidundefinedProperty-only: assign from script; not accepted as an attribute.
onViewReceipt——Recorded in the catalog without a top-level type; pinned from source when the row is ported.

Events

Events
EventUpstream propPayload typeNotes
detent-retryonRetry() => voidComposed, bubbles; fires only for a user action.
detent-change-payment-methodonChangePaymentMethod() => voidComposed, bubbles; fires only for a user action.
detent-download-receiptonDownloadReceipt() => voidComposed, bubbles; fires only for a user action.
detent-view-receiptonViewReceipt() => voidComposed, bubbles; fires only for a user action.

Slots

No slots are recorded for this component.

CSS customisation

  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • The receipt download is consumer-owned: upstream builds a Blob and clicks a synthetic <a download>; the native row exposes a read-only receiptText and emits detent-download-receipt, with zero network requests.
  • Framer Motion springs and AnimatePresence become CSS transitions plus hidden toggling so the live region stays mounted; the checkmark pathLength becomes stroke-dashoffset whose reduced-motion form is the fully drawn stroke.
  • Action boundaries use #6b6b6b instead of the upstream #1f1f1f to reach the WCAG 1.4.11 3:1 non-text ratio; dividers keep the hairline.
  • The pinned card was one fixed dark surface because the source has no dark: variants; this port follows the theme tokens in both colour schemes, and the --detent-payment-status-* custom properties still override every value.
  • errorMessage and refundReason are exposed as the error-message and refund-reason attributes pinned from source (the upstream meta omitted them), and the transaction-ID copy uses the async Clipboard API with the upstream execCommand fallback: a blocked clipboard never throws and never suppresses the confirmation.
  • Default demo copy and labels use Detent branding instead of EasyUI (pre-release rebrand).

What it does

A transaction status card: one of five lifecycle states with its own heading, subtext and indicator, a live announcement, the amount, the transaction metadata, an unfolding itemized receipt, a one-click transaction-ID copy and the failure recovery actions.

Upstream behaviour
  • 5 clear lifecycle states: Processing, Verifying, Success, Failed, and Refunded
  • Self-drawing SVG stroke checkmark animation upon payment confirmation
  • Staggered metadata reveal for amount, transaction hash, timestamp, and card info
  • Unfolding itemized receipt accordion with instant text-file receipt download
  • One-click transaction ID copying with instant checkmark feedback
  • Non-aggressive error state with instant retry and payment method alternatives
Differences from upstream
  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • The receipt download is consumer-owned: upstream builds a Blob and clicks a synthetic <a download>; the native row exposes a read-only receiptText and emits detent-download-receipt, with zero network requests.
  • Framer Motion springs and AnimatePresence become CSS transitions plus hidden toggling so the live region stays mounted; the checkmark pathLength becomes stroke-dashoffset whose reduced-motion form is the fully drawn stroke.
  • Action boundaries use #6b6b6b instead of the upstream #1f1f1f to reach the WCAG 1.4.11 3:1 non-text ratio; dividers keep the hairline.
  • The pinned card was one fixed dark surface because the source has no dark: variants; this port follows the theme tokens in both colour schemes, and the --detent-payment-status-* custom properties still override every value.
  • errorMessage and refundReason are exposed as the error-message and refund-reason attributes pinned from source (the upstream meta omitted them), and the transaction-ID copy uses the async Clipboard API with the upstream execCommand fallback: a blocked clipboard never throws and never suppresses the confirmation.
  • Default demo copy and labels use Detent branding instead of EasyUI (pre-release rebrand).
Previous: Payment Receipt Printer Next: Peek Card

Docs

Components

Project