Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Use PaymentElement para uma entrada de pagamento unificada que suporta cartões, carteiras e transferências bancárias. Use CardElement quando você precisar apenas de pagamentos com cartão e quiser controle mais refinado por campo. Estilize ambos usando a Appearance API da Stripe.
PaymentElement (recomendado para a maioria dos casos):
// app/checkout/payment-form.tsx
"use client";
import { PaymentElement, useStripe, useElements } from "@stripe/react-stripe-js";
import { useState, type FormEvent } from "react";
export function PaymentForm() {
const stripe = useStripe();
const elements = useElements();
const [error, setError] = useState<string | null>(null);
const [processing, setProcessing] = useState(false);
async function handleSubmit(e: FormEvent) {
e.preventDefault();
if (!stripe || !elements) return;
setProcessing(true);
const { error: submitError } = await elements.submit();
if (submitError) {
setError(submitError.message ?? "Erro de validação");
setProcessing(false);
return;
}
const { error: confirmError } = await stripe.confirmPayment({
elements,
confirmParams: { return_url: `${window.location.origin}/success` },
});
if (confirmError) {
setError(confirmError.message ?? "Falha no pagamento");
setProcessing(false);
}
}
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
{error && <p className="text-red-500 mt-2">{error}</p>}
<button type="submit" disabled={!stripe || processing}>
{processing ? "Processando..." : "Pagar"}
</button>
</form>
);
}CardElement (apenas cartão):
"use client";
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
import { useState, type FormEvent } from "react";
export function CardForm() {
const stripe = useStripe();
const elements = useElements();
const [error, setError] = useState<string | null>(null);
async function handleSubmit(e: FormEvent) {
e.preventDefault();
if (!stripe || !elements) return;
const cardElement = elements.getElement(CardElement);
if (!cardElement) return;
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: "card",
card: cardElement,
});
if (error) {
setError(error.message ?? "Erro");
} else {
// Envie paymentMethod.id para o seu servidor
console.log("PaymentMethod:", paymentMethod.id);
}
}
return (
<form onSubmit={handleSubmit}>
<CardElement options={{ style: { base: { fontSize: "16px" } } }} />
{error && <p className="text-red-500 mt-2">{error}</p>}
<button type="submit" disabled={!stripe}>Pagar</button>
</form>
);
}Um formulário de pagamento estilizado que combina com um aplicativo de tema escuro:
// app/checkout/styled-checkout.tsx
"use client";
import { useEffect, useState } from "react";
import { Elements } from "@stripe/react-stripe-js";
import type { Appearance } from "@stripe/stripe-js";
import { stripePromise } from "@/lib/stripe-client";
import { createPaymentIntent } from "@/app/actions/payment";
import { PaymentForm } from "./payment-form";
const appearance: Appearance = {
theme: "night",
variables: {
colorPrimary: "#6366f1",
colorBackground: "#1e1e2e",
colorText: "#e2e8f0",
colorDanger: "#ef4444",
fontFamily: "Inter, system-ui, sans-serif",
borderRadius: "8px",
spacingUnit: "4px",
},
rules: {
".Input": {
border: "1px solid #334155",
boxShadow: "none",
padding: "12px",
},
".Input:focus": {
border: "1px solid #6366f1",
boxShadow: "0 0 0 1px #6366f1",
},
".Label": {
fontWeight: "500",
fontSize: "14px",
},
".Tab": {
border: "1px solid #334155",
borderRadius: "8px",
},
".Tab--selected": {
backgroundColor: "#6366f1",
borderColor: "#6366f1",
},
},
};
export default function StyledCheckout() {
const [clientSecret, setClientSecret] = useState<string | null>(null);
useEffect(() => {
createPaymentIntent(4999).then(({ clientSecret }) => {
setClientSecret(clientSecret);
});
}, []);
if (!clientSecret) return <div className="text-white">Carregando...</div>;
return (
<div className="max-w-lg mx-auto p-8 bg-[#1e1e2e] rounded-xl">
<h2 className="text-xl font-bold text-white mb-6">Complete o Pagamento</h2>
<Elements
stripe={stripePromise}
options={{
clientSecret,
appearance,
layout: {
type: "tabs",
defaultCollapsed: false,
},
}}
>
<PaymentForm />
</Elements>
</div>
);
}PaymentElement é um único componente que renderiza dinamicamente campos de entrada para todos os métodos de pagamento habilitados (cartões, Apple Pay, Google Pay, débitos bancários, etc.). A Stripe determina quais métodos exibir com base na moeda, valor da transação e localização do cliente.CardElement renderiza uma entrada de cartão de linha única com campos de número, validade e CVC combinados. Ele suporta apenas pagamentos com cartão.theme, variables e rules. Temas (stripe, night, flat) fornecem uma base; variáveis substituem tokens de design; regras visam seletores específicos semelhantes a CSS para elementos individuais."tabs" os mostra como abas selecionáveis, "accordion" os mostra como seções expansíveis e "auto" deixa a Stripe decidir.Layout de acordeão:
<Elements
stripe={stripePromise}
options={{
clientSecret,
layout: { type: "accordion", defaultCollapsed: false, radios: true },
}}
>
<PaymentForm />
</Elements>Controlar a coleta de detalhes de faturamento:
<PaymentElement
options={{
layout: "tabs",
fields: {
billingDetails: {
name: "auto",
email: "never", // colete o e-mail você mesmo
phone: "never",
address: "auto",
},
},
}}
/>Campos de cartão divididos (CardNumber, CardExpiry, CardCvc):
import {
CardNumberElement,
CardExpiryElement,
CardCvcElement,
} from "@stripe/react-stripe-js";
function SplitCardForm() {
return (
<div className="space-y-4">
<div>
<label>Número do Cartão</label>
<CardNumberElement />
</div>
<div className="flex gap-4">
<div className="flex-1">
<label>Validade</label>
<CardExpiryElement />
</div>
<div className="flex-1">
<label>CVC</label>
<CardCvcElement />
</div>
</div>
</div>
);
}Appearance de @stripe/stripe-js para tipar sua configuração de aparência.PaymentElement aceita PaymentElementProps que inclui uma prop options tipada como PaymentElementOptions.CardElement usam CardElementOptions com uma API de estilização diferente (style.base, style.invalid, etc.) do que a Appearance API.import type { Appearance, LayoutObject } from "@stripe/stripe-js";
const layout: LayoutObject = {
type: "tabs",
defaultCollapsed: false,
};PaymentElement requer um clientSecret no provedor Elements. Você não pode usá-lo sem um PaymentIntent ou SetupIntent.CardElement usa um sistema de estilização diferente (prop style) do que PaymentElement (Appearance API). Eles não são intercambiáveis.PaymentElement e CardElement no mesmo provedor Elements. Escolha um.rules da Appearance API usam seletores personalizados da Stripe (.Input, .Label, .Tab), não seletores CSS padrão. Verifique a documentação para a lista completa.automatic_payment_methods está habilitado e se seu Painel Stripe tem outros métodos configurados.@font-face em seu CSS não estão automaticamente disponíveis dentro dos Stripe Elements. Passe-as através da opção fonts em Elements.| Abordagem | Prós | Contras |
|---|---|---|
| PaymentElement | Todos os métodos de pagamento, componente único, moderno | Requer clientSecret, menos controle granular |
| CardElement | Entrada de cartão de linha única e simples | Apenas cartões, API de estilização mais antiga |
| Campos de cartão divididos | Controle total do layout sobre cada campo | Mais marcação, apenas cartões |
| Stripe Checkout | Código de UI zero | Sai do seu site |
PaymentElement é um componente unificado que suporta cartões, carteiras, transferências bancárias e mais de 40 métodos de pagamento em um único componente.CardElement é uma entrada de linha única que suporta apenas pagamentos com cartão."tabs" -- métodos de pagamento mostrados como abas selecionáveis"accordion" -- métodos de pagamento mostrados como seções expansíveis"auto" -- a Stripe decide o melhor layouttheme base ("stripe", "night", "flat")variables (cores, fontes, raio da borda, espaçamento)rules usando seletores personalizados da Stripe (.Input, .Label, .Tab)Não. Você deve escolher um ou outro dentro de um único provedor <Elements>. Montar ambos causa conflitos e comportamento indefinido.
<PaymentElement
options={{
fields: {
billingDetails: {
name: "auto",
email: "never",
phone: "never",
address: "auto",
},
},
}}
/>Defina um campo como "never" se você o coletar em seu próprio formulário.
CardNumberElement, CardExpiryElement, CardCvcElementVerifique as configurações de método de pagamento do seu Painel Stripe. automatic_payment_methods mostra métodos que estão habilitados no Painel e são aplicáveis à moeda e localização do cliente na transação.
Os Stripe Elements renderizam dentro de iframes e não podem acessar fontes carregadas via @font-face no seu CSS. Você deve passar as fontes explicitamente através da opção fonts no componente <Elements>.
import type { Appearance, LayoutObject } from "@stripe/stripe-js";
const appearance: Appearance = {
theme: "night",
variables: { colorPrimary: "#6366f1" },
};
const layout: LayoutObject = { type: "tabs" };CardElement usa uma prop style com estados base, invalid e complete.PaymentElement usa a Appearance API com theme, variables e rules.Ela aceita PaymentElementOptions de @stripe/stripe-js, que inclui layout, fields, terms, wallets e outras configurações. Importe-a para segurança de tipo ao construir configurações dinâmicas.
Sim. Ao contrário do CardElement, o PaymentElement requer um clientSecret de um PaymentIntent ou SetupIntent passado através da prop options no <Elements>. Sem ele, o PaymentElement não renderizará.
Revisado por Chris St. John·Última atualização: 7 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥