1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オンライン決済サービスPAY.JPを使ってみた情報をシェアしよう! by PAYAdvent Calendar 2024

Day 14

PAY.JPの決済フォームを独自デザインで作る

Last updated at Posted at 2024-12-25

この記事は「オンライン決済サービスPAY.JPを使ってみた情報をシェアしよう! by PAY Advent Calendar 2024 」の14日目の記事です

はじめに

PAY.JPはチェックアウトライブラリを用いることで、<script> タグを一行書くだけで完成済みの決済フォームを実装することができます。
https://pay.jp/docs/checkout

image.png

非常に洗練されたデザインで、かつモーダルで表示されるので、自社プロダクトにスピーディーに組み込むことができそうです。
しかし、プロダクトによってはモーダルではなく既存の画面に組み込みたい, 自社のサービスのデザインルールに則るようにスタイリングを調整したいという要件は一般的によく発生します。

そんな時のために、この記事ではPAY.JPの決済フォームを独自デザインで作った時の記録を紹介しようと思います。

作ったもの

pay.gif

  • <input>にフォーカスがあるときは枠を緑色にする
  • <input>がエラー状態のときは背景と枠を赤色にする

実装

Reactで実装しました。
基本的には以下のドキュメントだけ読めば、実装を進められると思います。
https://pay.jp/docs/payjs

import { useState } from "react";
import type PayjpJs from "typedef-payjp-js";

const payjp = window.Payjp?.(
  "pk_test_xxxxxxxxxxxxxx"
) as PayjpJs.Payjp;

const App = () => {
  const [token, setToken] = useState("");

  let cardNumber: PayjpJs.PayjpElement | null = null;
  let cardExpiry: PayjpJs.PayjpElement | null = null;
  let cardCvc: PayjpJs.PayjpElement | null = null;

  const handleCardElementMounted = () => {
    const elements = payjp.elements();
    cardNumber = elements.create("cardNumber", {
      placeholder: "4242 4242 4242 4242",
    });
    cardExpiry = elements.create("cardExpiry", {
      placeholder: "12 / 29",
    });
    cardCvc = elements.create("cardCvc", {
      placeholder: "123",
    });
    cardNumber.mount("#card-number");
    cardExpiry.mount("#card-expiry");
    cardCvc.mount("#card-cvc");
  };

  const handleSubmit = async () => {
    if (!cardNumber) {
      alert("予期せぬエラーが発生しました。");
      return;
    }
    const token = await payjp.createToken(cardNumber);
    setToken(token.id);
  };

  return (
    <div id="payment-form" className="payment-form">
      <div>
        <div>カード番号</div>
        <div id="card-number" className="card-element" />
      </div>
      <div>
        <div>有効期限</div>
        <div id="card-expiry" className="card-element" />
      </div>
      <div>
        <div>セキュリティ番号</div>
        <div
          id="card-cvc"
          className="card-element"
          ref={handleCardElementMounted}
        />
      </div>
      <button
        id="submit-button"
        className="submit-button"
        onClick={handleSubmit}
      >
        get token
      </button>
      <div>token: {token}</div>
    </div>
  );
};

export default App;

CSSは以下のように実装しました。
https://pay.jp/docs/payjs#element-containerElementの状態によって付与されるクラスの一覧が記述されています。これを元にスタイリングしていきます

.payment-form {
  display: grid;
  gap: 8px;
  max-width: 400px;
  margin: 50px auto;
  padding: 20px;
  background: #f9f9f9;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.card-element {
  margin-top: 4px;
  border-radius: 5px;
  background: white;
  border: 1px solid #c2c8d2;
  border-radius: 4px;
  padding: 12px;
}

.PayjpElement--focus {
  border-color: #6ee7b7;
}

.PayjpElement--invalid {
  border-color: #dc2626;
  background-color: #fee2e2;
}

.submit-button {
  width: 100%;
  padding: 10px;
  margin-top: 20px;
  background: #4caf50;
  color: white;
  border: none;
  border-radius: 5px;
  font-size: 16px;
  cursor: pointer;
}

.submit-button:hover {
  background: #45a049;
}

終わりに

最後まで読んでいただきありがとうございました!

今回PAY.JPを色々触ってみた感想としては、ドキュメントが非常に読みやすく開発者に優しいサービスだと感じました。
また、決済フォームに関してはフォームの状態が常にDOMのクラスに反映され、またJavaScriptからも細かく取得できるようになっているので自社の要件に合った決済フォームを実装しやすいと感じました。

開発体験が非常によかったので、個人開発等で決済機能が必要になったときは積極的に使っていきたいと思っています。

参考資料

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?