This guide will show you how to integrate Stripe's Payment Element into a Nuxt 3 application to process payments for purchasing a cat. We'll cover setting up Stripe on both the client and server sides, and handling the payment process.
Prerequisites
- A Nuxt 3 application set up.
- Stripe account with API keys (STRIPE_SECRET_KEY and STRIPE_PUBLIC_KEY).
Step 1 - Install Stripe
Install the necessary Stripe packages:
npm install @stripe/stripe-js stripe
Step 2 - Configure Environment Variables
Add your Stripe API keys to the .env file.
NUXT_STRIPE_PUBLIC_KEY=your_public_key_here
STRIPE_SECRET_KEY=your_secret_key_here
Step 3: Create a Server API Endpoint
Create an endpoint to handle the creation of PaymentIntents. Create a file in this directory:server/api/stripe.js
import Stripe from 'stripe';
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
try {
const paymentIntent = await stripe.paymentIntents.create({
amount: Number(body.amount), // Amount in cents
currency: 'usd',
automatic_payment_methods: { enabled: true },
});
return {
client_secret: paymentIntent.client_secret
};
} catch (error) {
console.error('Error creating PaymentIntent:', error);
throw createError({
statusCode: 500,
statusMessage: 'Error creating payment intent',
});
}
});
Step 4: Set Up the Basic Nuxt Page
Create a component for purchasing a cat that integrates the Payment Element and handles the payment process.
pages/purchase/[catId].vue
<template>
<div>
<h1>Purchase Cat {{ catId }}</h1>
<div>
<p>Select your favorite cat and proceed to checkout.</p>
</div>
<!-- Payment form for Stripe Payment Element -->
<form @submit.prevent="pay">
<div class="border border-gray-500 p-2 rounded-sm" id="payment-element"></div>
<p id="payment-error" role="alert" class="text-red-700 text-center font-semibold"></p>
<button
:disabled="isProcessing"
type="submit"
class="mt-4 bg-gradient-to-r from-[#FE630C] to-[#FF3200] w-full text-white text-[21px] font-semibold p-1.5 rounded-full"
:class="isProcessing ? 'opacity-70' : 'opacity-100'"
id="processing"
aria-label="loading"
>
<p v-if="isProcessing">I'm processing payment</p>
<div v-else>Buy Now</div>
</button>
</form>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { loadStripe } from '@stripe/stripe-js';
import { useRuntimeConfig } from '#app';
// Accessing environment variables
const config = useRuntimeConfig();
const stripePk = config.public.STRIPE_PUBLIC_KEY;
const route = useRoute();
const catId = route.params.catId; // Get the cat ID from the URL
const isProcessing = ref(false);
let stripe;
let elements;
let paymentElement;
let clientSecret;
const total = 2000; // Example fixed amount for purchasing a cat in cents ($20)
onMounted(async () => {
await initializeStripe();
});
const initializeStripe = async () => {
stripe = await loadStripe(stripePk);
// Create a payment intent on your server
const res = await fetch('/api/stripe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: total // Fixed amount in cents
})
});
const result = await res.json();
clientSecret = result.client_secret;
elements = stripe.elements({ clientSecret });
// Create and mount the Payment Element
paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
isProcessing.value = false;
};
const pay = async () => {
isProcessing.value = true;
try {
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
payment_method_data: {
billing_details: {
name: 'John Doe',
email: 'john.doe@example.com',
phone: '+1234567890',
},
},
},
redirect: 'if_required' // Stay on the same page unless redirect is necessary
});
if (error) {
console.error('Payment error:', error);
document.querySelector('#payment-error').textContent = error.message;
isProcessing.value = false;
} else {
console.log('Payment succeeded');
// Handle post-payment success actions, like showing a success message
}
} catch (error) {
console.error('Payment processing error:', error);
document.querySelector('#payment-error').textContent = 'An error occurred. Please try again.';
isProcessing.value = false;
}
};
</script>
<style scoped>
/* Add any styles you want to apply to the purchase page */
</style>
This tutorial shows how to integrate Stripe's Payment Element into a Nuxt 3 application for a fictional online cat purchase scenario. You can further customize the form, handle additional payment methods, or expand functionality as needed.
For more detailed information, refer to the Stripe Payment Element documentation.
Top comments (5)
Great article! A suggestion:
I highly recommend some syntax highlighting for these code block.
I believe you can do this in md by adding jsx or whatever your language is immediately after the third backtick.
Thanks Julian, first time using dev.to to post code so I'll give it a whirl! 👍
Hello ! Don't hesitate to put colors on your
codeblock
like this example for have to have a better understanding of your code 😎I didn't know how to visualize this without doing it. I didn't even think of including a picture. Thanks for adding to the point haha!!
Haha! I should of done images and stuff, though I'd use it as a jumping off point 🤣