“Instant Checkout” Button in Vanilla JS + Fetch API

“Instant Checkout” Button in Vanilla JS + Fetch API

“Instant Checkout” Button in Vanilla JS + Fetch API

 

Creating seamless and fast user experiences is crucial in modern web development—especially in e-commerce. The “Instant Checkout” button is a perfect example of convenience, allowing users to purchase a product with a single click. In this article, we’ll build an “Instant Checkout” feature using only vanilla JavaScript and the Fetch API, communicating with a mock payment processor. No frameworks, no libraries—just clean, modern JavaScript.

1. Project Setup

To get started, create a simple HTML structure to display a product and add a checkout button. This makes testing intuitive and keeps the setup lightweight.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Instant Checkout</title>
</head>
<body>
  <div id="product">
    <h2>Wireless Mouse - $29.99</h2>
    <button id="checkoutBtn">Instant Checkout</button>
    <p id="status"></p>
  </div>

  <script src="checkout.js"></script>
</body>
</html>

Here, we define a product with a button labeled “Instant Checkout”. The checkout logic will live in checkout.js.

2. Making the Fetch Request

Let’s simulate a payment API endpoint using a mock service like https://reqres.in or your custom mock backend. When the button is clicked, we’ll fire a POST request representing the checkout process.

// checkout.js
document.getElementById('checkoutBtn').addEventListener('click', () => {
  const status = document.getElementById('status');
  status.textContent = 'Processing payment...';

  fetch('https://reqres.in/api/payments', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      productId: 1234,
      amount: 2999,
      currency: 'USD'
    })
  })
  .then(response => {
    if (!response.ok) throw new Error('Payment failed');
    return response.json();
  })
  .then(data => {
    status.textContent = 'Payment successful! Transaction ID: ' + (data.id || 'N/A');
  })
  .catch(error => {
    status.textContent = 'Error: ' + error.message;
  });
});

This script handles the click event, performs a POST request using Fetch, parses the JSON response, and updates the UI depending on the outcome. Even though we use a mock API, the same idea applies to production integrations.

3. Loading State and Button Disabling

To prevent accidental double-purchases and improve usability, it’s a good practice to disable the button during the async operation.

// Modify inside the click handler
const button = document.getElementById('checkoutBtn');
button.disabled = true;
status.textContent = 'Processing payment...';

fetch('https://reqres.in/api/payments', {
  ...
})
.then(...) // existing logic
.finally(() => {
  button.disabled = false;
});

The finally block ensures the button is re-enabled whether the request fails or succeeds—critical for a robust UI.

4. Optimization Tips and Real-World Enhancements

a. Use async/await: Modern JavaScript favors cleaner syntax. Rewriting our logic using async/await improves readability.

// Modernized checkout.js
async function handleCheckout() {
  const button = document.getElementById('checkoutBtn');
  const status = document.getElementById('status');

  button.disabled = true;
  status.textContent = 'Processing payment...';

  try {
    const response = await fetch('https://reqres.in/api/payments', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        productId: 1234,
        amount: 2999,
        currency: 'USD'
      })
    });

    if (!response.ok) throw new Error('Payment failed');
    const result = await response.json();
    status.textContent = `Payment successful! ID: ${result.id || 'N/A'}`;
  } catch (error) {
    status.textContent = 'Error: ' + error.message;
  } finally {
    button.disabled = false;
  }
}

document.getElementById('checkoutBtn').addEventListener('click', handleCheckout);

b. Retry logic: Add exponential backoff for retrying failed network requests in production scenarios.

c. Tokenization: Don’t send raw card data. In production, you’d interact with a payment gateway that tokenizes sensitive data.

5. Testing with Mock APIs

To make your integration more realistic, try tools like mockapi.io or Beeceptor to create endpoints that mimic real payment flows with status codes and body responses.

Example:

// Custom mock backend example
fetch('https://your-mock-endpoint.com/charge', {...})

By adjusting headers, response codes, and payloads, you can simulate conditions like failures, latency, or network drops. This helps build a resilient checkout flow before plugging into real gateways like Stripe or PayPal.

Final Thoughts

Implementing an “Instant Checkout” experience doesn’t require a full JavaScript framework or complex dependencies. Using vanilla JavaScript and Fetch API, you can quickly construct reliable e-commerce functionality. As always, performance, security, and error resilience should guide enhancements as your project grows.

This foundational pattern can easily evolve into a reusable function or module on larger projects—think payment alerts, modal confirmations, or even real-time order tracking. Simple code, big impact.

 

Useful links:

 

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *