-
Notifications
You must be signed in to change notification settings - Fork 0
components card fields
Import: import { CardFields } from "@tundralibs/ui/card-fields"
Rendered in every variant on the catalogue (deno task build:demos, then demo/index.html). Guides: Getting started · rAPId integration · Theming.
CardFields(props: CardFieldsProps): HtmlCard details as a group of FormFields — number (grouped as typed, brand
shown from the prefix), expiry (MM/YY, the slash inserted, not in the
past), name on card and CVC (3 digits, 4 for Amex — the number drives
it). Every part is a native input with autocomplete="cc-*", so
browsers and password managers fill it. Format checks only: length,
digits, expiry range, CVC length, plus the Luhn checksum when luhn is
set. Pair with Form({ validate: true }) for inline messages.
Rendering card fields means the card number reaches your server unless the form posts to a payment processor's endpoint — which puts the app in PCI scope. Use it knowingly.
"number""expiry""name""cvc"
| Prop | Type | Required | Description |
|---|---|---|---|
name |
string |
Base of the field names: <name>-number, <name>-expiry, <name>-name, <name>-cvc. @default "card" |
|
fields |
CardFieldPart[] |
Which parts to render, in this order. Number is always present. @default all four | |
required |
`boolean | Partial` | |
luhn |
boolean |
Also check the number's Luhn checksum (offline; catches a mistyped digit, says nothing about whether the card exists). Off by default — the format rules are length, digits, expiry range and CVC length. | |
labels |
Partial |
Field labels, for translation. | |
messages |
Partial & { expired?: string; luhn?: string } |
Validator messages per part, plus the two rules the script adds. | |
errors |
Partial |
Server-side errors per part (RapidFormError.fields[<name>-number] etc.), rendered like any FormField error. |
|
values |
Partial |
Values to re-render — name and expiry only. The number and CVC are never echoed back into markup, whatever is passed. | |
disabled |
boolean |
||
attrs |
Attrs |
Each example as the rAPId call and the HTML it renders — the markup a plain page writes by hand. Icons are inline SVG in the real output; they are shortened to <svg …>…</svg> here.
Format checks only; luhn: true adds the offline checksum. The number reaches your server unless the form posts to the payment processor — PCI scope is yours to decide.
CardFields({
name: "card",
luhn: true,
messages: { luhn: "Check the card number.", expired: "This card has expired." },
})<div class="card-fields" data-card-fields data-luhn="">
<div class="form-grid">
<div class="form-field">
<label class="form-field__label" for="card-number">
Card number
<span class="form-field__required" aria-hidden="true">*</span>
</label>
<div class="input-group card-fields__number-group">
<input type="text" class="input input-group__control card-fields__number" inputmode="numeric" data-card-number="" data-msg-luhn="Check the card number." id="card-number" name="card-number" placeholder="1234 5678 9012 3456" required="" maxlength="23" pattern="[0-9 ]{13,23}" autocomplete="cc-number">
<span class="input-group__addon card-fields__brand" data-card-brand aria-live="polite"></span>
</div>
</div>
<div class="form-field form-grid__col-6">
<label class="form-field__label" for="card-expiry">
Expiry
<span class="form-field__required" aria-hidden="true">*</span>
</label>
<input type="text" class="input" inputmode="numeric" data-card-expiry="" data-msg-expired="This card has expired." id="card-expiry" name="card-expiry" placeholder="MM/YY" required="" maxlength="5" pattern="(0[1-9]|1[0-2])/[0-9]{2}" autocomplete="cc-exp">
</div>
<div class="form-field">
<label class="form-field__label" for="card-name">
Name on card
<span class="form-field__required" aria-hidden="true">*</span>
</label>
<input type="text" class="input" data-card-name="" id="card-name" name="card-name" required="" autocomplete="cc-name">
</div>
<div class="form-field form-grid__col-6">
<label class="form-field__label" for="card-cvc">
CVC
<span class="form-field__required" aria-hidden="true">*</span>
</label>
<input type="text" class="input" inputmode="numeric" data-card-cvc="" id="card-cvc" name="card-cvc" placeholder="123" required="" maxlength="3" pattern="[0-9]{3}" autocomplete="cc-csc">
</div>
</div>
</div>A stored card's renewal wants the number and a new expiry; a merchant-initiated charge has no CVC.
CardFields({ name: "stored", fields: ["number", "expiry"] })<div class="card-fields" data-card-fields>
<div class="form-grid">
<div class="form-field">
<label class="form-field__label" for="stored-number">
Card number
<span class="form-field__required" aria-hidden="true">*</span>
</label>
<div class="input-group card-fields__number-group">
<input type="text" class="input input-group__control card-fields__number" inputmode="numeric" data-card-number="" id="stored-number" name="stored-number" placeholder="1234 5678 9012 3456" required="" maxlength="23" pattern="[0-9 ]{13,23}" autocomplete="cc-number">
<span class="input-group__addon card-fields__brand" data-card-brand aria-live="polite"></span>
</div>
</div>
<div class="form-field form-grid__col-6">
<label class="form-field__label" for="stored-expiry">
Expiry
<span class="form-field__required" aria-hidden="true">*</span>
</label>
<input type="text" class="input" inputmode="numeric" data-card-expiry="" id="stored-expiry" name="stored-expiry" placeholder="MM/YY" required="" maxlength="5" pattern="(0[1-9]|1[0-2])/[0-9]{2}" autocomplete="cc-exp">
</div>
</div>
</div>Classes defined by components/card-fields/card-fields.css — structural, token-driven; override from an unlayered stylesheet (see Theming):
.card-fields, .card-fields__brand, .card-fields__number
components/card-fields/card-fields.js ships in ui.js (delegated on document, re-initialised after a rAPId swap).
Attributes it reads or writes: data-brand, data-card-brand, data-card-cvc, data-card-expiry, data-card-fields, data-card-number, data-luhn, data-msg-expired, data-msg-luhn, data-msg-pattern.
Events: rapid:swapped.
Guides
Reference