Skip to content

components card fields

GitHub Actions edited this page Sep 22, 2026 · 1 revision

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.

Functions

CardFields

CardFields(props: CardFieldsProps): Html

Card 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.

Types

CardFieldPart

  • "number"
  • "expiry"
  • "name"
  • "cvc"

CardFieldsProps

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

Usage

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.

Card details, all four parts

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>

Only the parts a flow needs

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>

CSS hooks

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

Behaviour

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.

Clone this wiki locally