3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ReactとStripe Elementで作成した決済フォームの、CSS・見た目をカスタマイズする方法

Posted at

Stripe Elementsで描画される決済フォームは、セキュリティなどの目的でiframeの中に配置されます。

スクリーンショット 2022-11-21 18.45.56.png

そのため、CSSでの内容・見た目のカスタマイズはElement Appearance APIを利用して行う必要があります。

この記事では、Payment Elementsの見た目を調整する方法を紹介します。

プリセットスタイル(テーマ)で設定する

StripeのPayment Elementsでは、いくつかのスタイルプリセットが用意されています。

スクリーンショット 2022-11-21 17.58.10.png
ドキュメントサイトでデモを見る

これらは、<Elements/>options.appearanceで設定します。

    <Elements
      stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY)}
      options={{
        appearance: {
          theme: 'stripe'
        },
        clientSecret: piClientSecret,
      }}
    >

Darkモード用のテーマも用意されています。

スクリーンショット 2022-11-21 18.24.08.png

以下のサンプルでは、prefers-color-schemeを利用して、動的にテーマを切り替えます。

export default function Root() {
  
  /**
   * Payment Intentを作成する処理
   * React v18以降でのuseEffectが2回実行される挙動を、useRefを利用して抑止するワークアラウンドを追加
   **/
  const hasAPICalledRef = useRef(false)
  const [piClientSecret, setPiClientSecret] = useState('')
  useEffect(() => {
    if (hasAPICalledRef.current) return
    hasAPICalledRef.current = true
    fetch('http://localhost:3000/create_payment_intent', {
      method: 'post'
    }).then(data => data.json())
      .then(response => setPiClientSecret(response.clientSecret))
  }, [])

  /**
   * ブラウザの設定がダークモードか否かを判定する処理
   **/
  const [isDarkMode, setIsDarkMode] = useState(false)
  useEffect(() => {
    // Next.jsを想定したSSR対策
    if (!window) return

    // Stateを更新する処理
    const onSelectColorScheme = (e: {matches:boolean}) => {
      setIsDarkMode(e.matches)
    }

    // ブラウザの設定が変わったことを検知するイベントリスナーを追加
    window.matchMedia('(prefers-color-scheme: dark)')
      .addEventListener('change', onSelectColorScheme)
    
    // 初回読み込み時の判定処理
    const isDarkMode = window?.matchMedia('(prefers-color-scheme: dark)').matches
    onSelectColorScheme({
      matches: isDarkMode
    })
    
    return () => {
      // unmount時にイベントリスナーを解除
      window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', onSelectColorScheme)
    }
  },[])


  if (!piClientSecret) return null;
  return (
    <Elements
      stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY as string)}
      options={{
        appearance: {
          // 通常とダークモードでテーマが変わるように設定
          theme: isDarkMode ? 'night' : 'stripe',
        },
        clientSecret: piClientSecret, 
      }}
    >
      <Home />
    </Elements>
  )
}

CSS変数をカスタマイズする

ElementsのCSSには、CSS Variablesが設定されています。

この値をAppearance APIから変更することで、フォントや色・マージンなどを調整できます。

    <Elements
      stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY)}
      options={{
        appearance: {
          theme: 'stripe',
          variables: {
            colorPrimary: '#2b8501',
            colorBackground: '#eeeeee',
            colorText: '#54883c',
            colorDanger: '#654321',
            fontFamily: 'Osaka',
            spacingUnit: '5px',
            borderRadius: '4px',
            spacingTab: '10px',
            spacingGridRow: '20px',
            spacingGridColumn: '50px'
          },
        },
        clientSecret: piClientSecret,
      }}
    >

テキストやフォームの背景色を変更できました。

スクリーンショット 2022-11-21 18.32.00.png

利用できる変数名は、ドキュメントのCommonly used bariablesLess commonly used variablesをご確認ください。

RulesでCSSを上書きする

CSS変数だけではカスタマイズできない箇所がある場合、CSSをJSオブジェクトとして上書きできます。

options.appearance.rulesに、「クラス名 - ルール」で定義しましょう。

    <Elements
      stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY)}
      options={{
        appearance: {
          theme:  'stripe',
          rules: {
            '.Tab': {
              borderRadius: '0',
              border: '1px solid #E0E6EB',
              boxShadow: '0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02)',
            },      
            '.Tab:hover': {
              color: 'var(--colorText)',
            },      
            '.Tab--selected': {
              borderColor: '#E0E6EB',
              boxShadow: '0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02), 0 0 0 2px var(--colorPrimary)',
            },          
            '.Input': {
              borderRadius: '0',
            },  
            '.Input--invalid': {
              boxShadow: '0 1px 1px 0 rgba(0, 0, 0, 0.07), 0 0 0 2px var(--colorDanger)',
            },
          }
        },
        clientSecret: piClientSecret,
      }}
    >

このサンプルでは、borderの色や曲がり具合などをカスタマイズしています。

スクリーンショット 2022-11-21 18.39.47.png

利用できるルール(クラス名やステートなど)は、ドキュメントにて確認できます。

プリセット(テーマ)を使わずに見た目を調整する

VariablesとRulesを利用して、独自のデザインを設定することもできます。

その場合、theme: 'none'設定しましょう。


    <Elements
      stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY)}
      options={{
        appearance: {
-          theme: 'stripe'
+          theme: 'none'
        },
        clientSecret: piClientSecret,
      }}
    >

Stripe側による見た目の装飾が最小限になります。

スクリーンショット 2022-11-21 18.01.17.png

あとはoptions.appearance.variablesoptions.appearance.rulesを利用してカスタマイズしましょう。


    <Elements
      stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY)}
      options={{
        appearance: {
          theme:  'none',
          variables: {
            colorPrimary: '#2b8501',
            colorDanger: '#654321',
            fontFamily: 'Osaka',
            spacingUnit: '5px',
            borderRadius: '4px',
            spacingGridColumn: '50px'
          },
          rules: {
            '.Tab': {
              border: '1px solid #E0E6EB',
              boxShadow: '0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02)',
            },      
            '.Tab:hover': {
              color: 'var(--colorText)',
            },      
            '.Tab--selected': {
              borderColor: '#E0E6EB',
              boxShadow: '0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02), 0 0 0 2px var(--colorPrimary)',
            },          
            '.Input': {
              border: '1px solid #E0E6EB',
              boxShadow: '0px 1px 1px rgba(0, 0, 0, 0.03), 0px 3px 6px rgba(18, 42, 66, 0.02, 0 0 0 2px var(--colorPrimary))',
            },  
            '.Input--invalid': {
              boxShadow: '0 1px 1px 0 rgba(0, 0, 0, 0.07), 0 0 0 2px var(--colorDanger)',
            },
          }
        },
        clientSecret: piClientSecret,
      }}
    >

スクリーンショット 2022-11-21 18.44.43.png

[PR] Stripe開発者向け情報をQiitaにて配信中!

  • [Stripe Updates]:開発者向けStripeアップデート紹介・解説
  • ユースケース別のStripe製品や実装サンプルの紹介
  • Stripeと外部サービス・OSSとの連携方法やTipsの紹介
  • 初心者向けのチュートリアル(予定)

など、Stripeを利用してオンラインビジネスを始める方法について週に2〜3本ペースで更新中です。

-> Stripe Organizationsをフォローして最新情報をQiitaで受け取る

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?