payjp.js v1 移行ガイド

ここでは、payjp.js v1 をご利用の方向けに、v1 の提供終了に伴うマイグレーションについて説明します。

移行先の選定

v1 をご利用の場合、加盟店によってクレジットカード情報の入力フォームが用意されていることが一般的です。

フォームのデザインを変えたくない場合は、payjp.js v2の分割フォームを利用して再実装いただく必要があります。

弊社が用意したデザインへの変更を許容できる場合は、Web であればCheckout、または、payjp.js v2 を type=card でご利用ください。 モバイルであれば、モバイル SDK の利用を検討ください。 モバイル SDK はiOSAndroidFlutterReact Nativeを用意しております。

移行先 Checkout v2 type=card v2 分割フォーム iOS/Android Flutter/React Native
デザイン 弊社提供 弊社提供 自由 弊社提供 弊社提供
工数の目安 中〜大 中〜大
JavaScriptの知識 不要 必要 必要 不要 必要

移行によりできなくなること

v1 廃止の目的でもありますが、いずれの移行先においても、カード番号・有効期限・CVC の値は取得できなくなります。

これに伴い、以下のことができなくなります。

  1. カード番号からブランド情報を自身で判定すること
  2. カード番号・有効期限・CVC を自身でバリデーションすること
  3. カード番号を取得してカード会社情報を判定すること

その代わりに、移行先ライブラリが 1 や 2 の処理を行います。 ただし 3 についてはセンシティブ情報に区分されるため、今後情報を取得できなくなります。

たとえば 1 について、Checkout では、入力されたカード番号からブランド判定をリアルタイムで UI に反映し、 利用できないブランドでリクエストされた場合はエラーを表示します。 payjp.js v2 では JavaScript を介してカードブランド情報をリアルタイムに通知し、さらに type=card の場合はリアルタイムでブランドロゴを表示します。

v2への移行について

以下では、payjp.js v2 へ移行される場合の説明を行います。 その他の移行先については、各ドキュメントをご参考ください。

デザインの制限

v2 を利用される場合、デザイン面において、以下のことができなくなります。

  1. 有効期限フォームに select タグを使うこと
  2. input タグの required 属性による UI 表現
  3. CVC などの input タグに type=password 属性を付与すること
  4. 入力フォーム(input タグ)に利用可能ではない CSS プロパティを適用すること
  5. input タグへの Web Font の利用(近日実装予定)

1 については、最近の決済フォームデザインの流行や利便性を鑑みての判断となります。 たとえば 02/22222 と入力すればよく、スラッシュ・0 埋めなどの整形は自動で行われます。 また、多くのモバイルではデフォルトで数字キーが立ち上がります。

2 の属性があると、空欄で form.submit()が行われた際に「このフィールドを入力してください」というブラウザ実装の警告が出ます。 しかし iframe 化により利用できなくなります。

3 は、PCI-DSS における要件ではありませんが、モバイル SDK ではデフォルトで表示が隠れる仕様となっております。

4 について、利用可能な CSS プロパティについてはこちらを確認ください。

できるようになること

  1. 3D secure
  2. Apple Pay on the Webの最新バージョンの利用(近日実装予定)

移行の要点

・inputタグはiframe内に作られる

現在お使いの CSS や JavaScript、外部ライブラリが、フォームの input タグを参照している場合、適用されなくなるため改修が必要となります。 とくにライブラリ側でワークアラウンドがなく利用できない場合には、自身でライブラリに相当する内容を再実装する必要が生じます。 本ページの移行例ではそうしたケースを取り扱っております。

なお、v2 が生成する input タグへ、CSS やイベント検知を適用することは可能です。

また、名義などの任意入力項目についてはご自身で用意いただくため、従来の実装をそのままご利用可能です。

・ライブラリの初期化方法の変更

payjp.js ではライブラリを読み込むことで使用可能になる Payjp という変数を利用します。

v1 ではこの変数の型は object のため、Payjp.setPublicKey(key)Payjp.createToken() のように呼び出します。

一方 v2 では変数の型は関数であり、初めに const payjp = Payjp(key) とインスタンスを生成して、payjp.createToken() などを呼び出します。 この初期化処理における引数のオプションなどはAPIドキュメントを参考ください。

・Payjp Element

Payjp Element とは、入力フォームを管理する JavaScript オブジェクトです(文脈によって、入力フォーム自体を指す場合もあります)。 これを自身の DOM 上に mount() して、入力フォームを持つ iframe を生成します。

const elements = payjp.elements()
const cardElement = elements.create('card') // Payjp Elementを生成
cardElement.mount('#id') // 入力フォームを配置

Payjp Element は大きく2種類存在します。

  1. type=card: カード番号・有効期限・CVC の入力フォームが一体となった固定デザイン
  2. type=cardNumber,cardExpiry,cardCvc: それぞれを独立したフォームとして扱う分割デザイン

既存フォームのデザインを維持したい場合は 2 をご利用ください。

移行例

ここでは payjp.js v1 を使ってマテリアルデザイン調に作られた決済フォームを v2 へ移行する例について解説します。

v1 v2
デザイン
フォームURL https://payjp.github.io/sample/payjp-js/v1.html https://payjp.github.io/sample/payjp-js/index.html

フォームのソースコードはこちらを確認ください。 ソースコードは MIT ライセンスでご利用いただけます。

このフォームは、カード番号・有効期限(月)・有効期限(年)・CVC・カード名義を入力後にボタンを押すことでトークンを生成します。 これを基本的なデザインは変えずに v2 を利用したフォームへと移行させます。

例外として、v2 の有効期限入力フォームは月と年でまとまったもののみを提供しているため、移行後のフォームではそのデザインにしたがっています。

注意: 例は事前ビルドを必要としない構成で記述されてます。

1. 課題の確認

この v1 決済フォームは、マテリアルデザインのライブラリであるMaterial Component Web(以下 MDC ライブラリと表記)を使って作られています。 このライブラリは指定の class 名を当てることで、マテリアルデザイン準拠の入力フォームを簡単に実現できます。 以下は mdc- という接頭辞の class 名を使ってText fieldsコンポーネントを実現しています。

<script type="text/javascript" src="https://js.pay.jp/v1/"></script>
<script
  src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js">
</script>
<link
  href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css"
  rel="stylesheet" />
<!-- 中略、以下カード番号の入力フォーム -->
<label class="field mdc-text-field mdc-text-field--filled">
  <span class="mdc-text-field__ripple"></span>
  <span class="mdc-floating-label">カード番号</span>
  <input id="v1-card-number"
         class="mdc-text-field__input"
         autocomplete="cc-number"
         autocorrect="off"
         spellcheck="false"
         inputmode="numeric"
         placeholder="4242 4242 4242 4242"
         required
  >
  <span class="mdc-line-ripple"></span>
</label>
<!-- カード番号の入力フォームここまで、以下中略 -->
<script src="mdc.js"></script>
<script type="text/javascript">
  setUpMDC() // MDCライブラリの初期化処理
</script>

v2 移行を行うと、input タグが別ドメインの iframe 内へ移るため、class 名を当てたり JavaScript や CSS を直接適用できず、Text fields コンポーネントをそのまま使うことができません(※注)。

次項から元のデザインを実現するために必要な作業を見ていきましょう。

注意: iframe 化されるフォームはカード番号・有効期限・CVC のみとなります。 カード名義のフォームは移行不要なので、Text fields コンポーネントをそのまま使うことができ、この例においてはそのまま残しています。

2. Payjp Elementの利用

まずは、元デザインのカード情報入力フォームである input タグを、v2 の入力フォームである Payjp Element に置き換えましょう。

Payjp Element の基本的な使い方は簡単です。

HTML の変更としては、カード番号・有効期限・CVC の input タグを div タグに変更するだけです。 div タグにはユニークな id を必ず付けてください。 また今回のように label タグを利用している場合、for 属性にその ID を指定することで、label タグの領域を click 時に自動的に Payjp Element へ focus を移すことが可能です。

<script type="text/javascript" src="https://js.pay.jp/v2/"></script>
<!-- 中略 -->
<label
  class="field mdc-text-field mdc-text-field--filled"
  for="v2-mdc-card-number"
>
  <span class="mdc-text-field__ripple"></span>
  <span class="mdc-floating-label">カード番号</span>
  <div id="v2-mdc-card-number" class="mdc-text-field__input"></div>
  <span class="mdc-line-ripple"></span>
</label>
<!-- 中略。以下、有効期限についてはも同様 -->
<label
  class="field mdc-text-field mdc-text-field--filled"
  for="v2-mdc-card-expiry"
>
  <span class="mdc-text-field__ripple"></span>
  <span class="mdc-floating-label">有効期限</span>
  <div id="v2-mdc-card-expiry" class="mdc-text-field__input"></div>
  <span class="mdc-line-ripple"></span>
</label>
<!-- 以下、CVCについても同様 -->

そして以下の JavaScript を実行し、div タグに Payjp Element をmount()しましょう。

// setUpMDC()以外の処理は削除やコメントアウトして以下を記述
const payjp = Payjp('pk_test_0383a1b8f91e8a6e3ea0e2a9')
const elements = payjp.elements()

// 入力フォーム毎にElementオブジェクトを生成する
const numberElement = elements.create('cardNumber')
const expiryElement = elements.create('cardExpiry')
const cvcElement = elements.create('cardCvc')
numberElement.mount('#v2-mdc-card-number')
expiryElement.mount('#v2-mdc-card-expiry')
cvcElement.mount('#v2-mdc-card-cvc')

ここまでの変更で、input タグを弊社ドメインの iframe 内へ移行できました。これにより、本質的には v2 への移行が完了したことになります。

しかし、現状では以下の図のように、一部のデザインが適用されていなかったり、カード番号・有効期限・CVC の入力欄がクリックできない状態です。またコンソールでは MDC ライブラリからの警告が出力されています。 これは、MDC ライブラリのデザイン生成には input タグの存在が必要ですが、それらが iframe に隠れてしまったため、正しく機能していないためです。

3. Elementコンテナーの利用

このように、デザインライブラリが input タグに依存しており、iframe 型決済用のワークアラウンドがない場合は、デザインライブラリ相当の JavaScript や CSS を自身で用意する必要があります。

MDC ライブラリのText fieldsコンポーネントが適用している CSS を調べ、そのうち input タグ以外の CSS を最小限にまとめたものがmdc-on-v2.cssです。 (MDC ライブラリの class 名と重複しないように、 mdc- の接頭辞を除いた命名で class 名を新しく作成しています。その際、 mdc-text-field--filled 相当の CSS は text-field にまとめています)

<link rel="stylesheet" type="text/css" href="mdc-on-v2.css" />
<!-- 上の読み込みを追加し、各label内のclass名を修正 -->
<label class="field text-field" for="v2-mdc-card-number">
  <span class="text-field__ripple"></span>
  <span class="floating-label">カード番号</span>
  <div id="v2-mdc-card-number" class="text-field__input"></div>
  <span class="line-ripple"></span>
</label>

MDC ライブラリを使用しなくなったため、コンソールエラーは解消されます。 しかし、現状では入力フォームに focus した際のラベルのフローティングが移行前のように動作しません。 以下のようにラベルとプレースホルダーが重なってしまいます。

MDC ライブラリは、input タグへの focus や input イベントに応じて、label タグに状態を表す class 名を追加し、適用する CSS を変更することでラベルのフローティングを実現していました。

label.mdc-text-field--focus .mdc-floating-label {
  /* focus時にラベルをフローティング */
}

しかし、v2 を利用する場合、直接 input タグのイベントを検知できません。

解決方法として後述する v2 でのイベント検知を使った方法もありますが、CSS への活用に限ればElementコンテナが便利です。

Element コンテナーとは、MDC ライブラリが行っているような、input タグの状態を表す class 名をマウント先に付与する仕組みです。 入力フォームが focus 状態の時は PayjpElement--focus というクラス名が自動的に div タグに付与されるので、それに合わせて CSS を変更しましょう。

div.PayjpElement--focus ~ .floating-label {}

なお、この例では先述の CSS と比べて兄弟関係を指定するセレクター(~)を利用しています。 label タグに class 名が付与される場合であれば、フローティングラベル要素((mdc-)floating-label クラス)は子孫コンビネーターを使って実現できますが、 Element コンテナーが働く div タグはフローティングラベル要素と同じ階層の要素のため、指定には工夫が必要になります。 この例では div タグの位置を label タグ直下に移動し、兄弟関係を指定するセレクターを利用しました。

<label class="field text-field" for="v2-mdc-card-number">
  <!-- Payjp Elementを上に -->
  <div id="v2-mdc-card-number" class="text-field__input">
  </div>
  <span class="text-field__ripple"></span>
  <span class="floating-label">カード番号</span><!-- フローティングラベル要素を下に -->
  <span class="line-ripple"></span>
</label>

次項では、残るデザイン上の差異である、input タグへの CSS とプレースホルダーの指定について見ていきましょう。

4. inputタグへのデザイン適用

iframe 内の input タグへの CSS やプレースホルダーの適用は、Payjp Element の初期化時、及び更新時の引数で JavaScript を介して行います。

2のPayjp Element初期化時のコードに引数 style や placeholder を指定してみましょう。

const payjp = Payjp('pk_test_0383a1b8f91e8a6e3ea0e2a9')
const elements = payjp.elements()

// styleオブジェクトの詳細は以下を参照
// https://pay.jp/docs/payjs#style
const elementStyle = {
  base: { // 常に適用したいCSSを以下に記述
    // CSSプロパティ名はキャメルケースで指定
    fontFamily: '\'Noto Sans Japanese\', sans-serif',
    '::placeholder': { // 疑似クラスや疑似要素も指定可能 
      color: 'rgba(0, 0, 0, 0.54)',
    },
    caretColor: '#198FCC',
    lineHeight: '28px', // inputタグのheightを定義
  },
  // フォームに無効な文字列が入っている場合、
  // baseの値を継承しつつ、以下の値のみ上書きする
  invalid: {
    color: 'rgba(0, 0, 0, 0.87)',
  },
}

const numberElement = elements.create('cardNumber', {
  style: elementStyle,
  placeholder: '4242 4242 4242 4242'
})
const expiryElement = elements.create('cardExpiry', {
  style: elementStyle,
})
const cvcElement = elements.create('cardCvc', {
  style: elementStyle,
})
numberElement.mount('#v2-mdc-card-number')
expiryElement.mount('#v2-mdc-card-expiry')
cvcElement.mount('#v2-mdc-card-cvc')

5. イベント検知

フォームの内容が不正であればエラーメッセージを出し、完了していればトークン生成ボタンを押下可能にする、といった判定処理を自身で実装する必要はありません。 Payjp Element はユーザーの入力状況に応じてバリデーションを行い、結果をイベントとして通知します。

element.on() または element.addEventlistener() を使って、イベント検知を行いましょう。 検知可能なイベントは以下となります。

  • focus : フォームがフォーカスされたときに通知
  • blur : フォームがフォーカスを失ったときに通知
  • ready : フォームのレンダリングが完了したときに通知
  • change : フォームの値が変更されたときに通知

もっとも情報量が多いイベントは change イベントです。 入力が完了したかどうか、エラーはないか、カードブランドは何か、などを検知できます。

// 注. 以下、実装は一部省略や簡略化しています
// Element毎にイベントリスナーを用意
numberElement.on('change', function(event) { 
  /*
    (eventの値の例) = {
      // expiryElement, cvcElementの場合はこの情報はない
      brand: 'Visa', 
      complete: false,
      elementType: 'cardNumber',
      empty: false,
      error: {
        message: '入力が完了していません。',
        code: 'incomplete_error'
      }
    }
  */
  if (event.error) { // error=nullでなければ入力値は不正
    // メッセージはerror.messageをそのまま使うかerorr.codeから自作する
    displayErrorMsg(event.error.message) 
  } else {
    if (errors) {
      displayErrorMsg(errorMsg)
    } else  { // 全Elementでエラーがなければ
      errorElm.classList.remove('visible') // エラーメッセージを隠す
      if (completes) { // 全Elementでcomplete=trueになったら
        buttonElm.removeAttribute('disabled') // ボタンを押下可能に
      }
    }
  }
})

なお、MDC ライブラリでは、required 属性のついた input タグが focus された後で入力せずに blur するとエラー扱いとなります。 v2 ではデフォルトではエラー扱いとはなりません。 この例では実装していませんが、focus および blur イベントと element.update()などを組み合わせて挙動を合わせることができます。

6. トークン生成

トークン生成には v1 と同じ関数名のpayjp.createToken()を利用します。

第一引数には Payjp Element をどれか1つ渡します。どの Element を渡しても大丈夫です。

第二引数にはカード名義などの任意引数や、Platform をご利用の場合は tenant を渡します。

// 注. 以下、実装は一部省略や簡略化しています
form.addEventListener('submit', function(e) {
  e.preventDefault()

  const options = {
    card: {
      name: nameInput.value || undefined // カード名義フォームから値を取得
    }
  }

  payjp.createToken(numberElement, options).then(function(result) {
    // resultはToken objectまたはError object
    // APIドキュメントを参照: https://pay.jp/docs/api/
    if (result.id) { // トークンIDがあれば成功、resultはToken object
      section.querySelector('.token').innerText = result.id
    } else { // resultはError object
      displayErrorMsg(result.error.message)
    }
  })
})

トークン生成後、入力内容をクリアしたい場合、form.reset() では iframe 内の入力内容を初期化できません。 element.clear() をご利用ください。 その際、Element コンテナも初期化されるため、MDC ライブラリが付与する class 名の初期化処理は不要となります。

v2 の機能とは直接関係しない部分については一部説明を省略させていただきましたが、以上が移行の解説となります。

FAQ

Ionicなどのモバイルフレームワークでの利用について

ionic/capacitor 環境において payjp.js v2 は利用可能です。 ionic/cordova 環境における payjp.js v2 の動作は未確認となっております。

なお、専用のモバイル SDK はiOSAndroidFlutterReact Native向けに用意しています。

モバイルの主要ブラウザ上では payjp.js v2 は正常に動作します。 上記以外のモバイルフレームワークにおいては、決済フォーム部分を外部ブラウザへの遷移で誘導したり、アプリ内ブラウザの利用などを検討ください。

モバイルのWebView内でのv2の利用について

基本的な動作は確認できております。

ただし、モバイルの WebView において 3D Secure サブウィンドウ型が動作しないケースを確認しております。 代替案としてリダイレクト型を用意しておりますので、そちらをご利用ください。

React.jsやVue.jsなどのWebフレームワークにv2を組み込めますか

はい、React.js や Vue.js などの Web フレームワークに Payjp.js v2 を問題なく組み込んでご利用いただけます。 ただし、注意点がいくつかあります。

まず、Payjp.js は npm install してご利用いただくことはできません。 ライブラリの性質上、今後も npm などのパッケージマネージャーでのご提供は致しません。 必ず script タグから読み込んでください。

次に、Payjp.js v2 の各 API の実行タイミングとフレームワークのライフサイクルについてご注意ください。 たとえば、element.mount(selector: string)は引数を内部で document.querySelector() に渡しています。 そのため、実行時に対象の要素がレンダリング済みでないとエラーが発生します。 Vue.js を例にとると、created()のタイミングだとエラーが発生するため、mounted()など要素がレンダリングされた後に実行する必要があります。

分割デザインでカード番号の入力が完了したら自動で有効期限へfocusを移せますか

分割デザインの場合、ご自身でelement.focus()element.blur()を活用して実装いただく必要があります。

たとえば、カード番号の Element をイベント監視し(numberElement.on('change', fn))、complete=true となったら有効期限の Element を focus する(expiryElement.focus())といった具合です。

なお、type=card を使用する場合は、デフォルトでその挙動をいたします。