Using Lemon.js with Frameworks and Libraries

Modern JS frameworks and libraries may require a different approach to integrating Lemon.js.


Next.js

To optimize the loading of the script, use the Next.js inbuilt next/script Script component. By default the strategy is set to afterInteractive, which is the recommended strategy for Lemon.js.

From Next.js documentation:

Scripts that use the afterInteractive strategy are injected into the HTML client-side and will load after some (or all) hydration occurs on the page. This is the default strategy of the Script component and should be used for any script that needs to load as soon as possible but not before any first-party Next.js code.

Embed Lemon.js in Next.js

import Script from "next/script";
 
export default function CheckoutPage() {
  return (
    <>
      <Script src="https://app.lemonsqueezy.com/js/lemon.js" />
 
      <div className="container py-20 mx-auto">
        <h1 className="text-4xl mb-10">Checkout</h1>
      </div>
    </>
  );
}

Add your Lemon Squeezy button

<a href="https://[STORE].lemonsqueezy.com/checkout/buy/[VARIANT_ID]" className="lemonsqueezy-button">Purchase my Product</a>

Replace the above link with your actual product link.

Final code

import Script from "next/script";
 
export default function CheckoutPage() {
  return (
    <>
      <Script src="https://app.lemonsqueezy.com/js/lemon.js" />
 
      <div className="container py-20 mx-auto">
        <h1 className="text-4xl mb-10">Checkout</h1>
        <a href="https://[STORE].lemonsqueezy.com/checkout/buy/[VARIANT_ID]" className="lemonsqueezy-button">Purchase my Product</a>
      </div>
    </>
  );
}

React

In React, you can use the useEffect hook to load Lemon.js. This will ensure that Lemon.js is loaded only once when the component mounts.

Create a new component and use the useEffect hook to load Lemon.js.

import { useEffect, useState } from "react";
 
export function BuyButton() {
  const [lemonLoaded, setLemonLoaded] = useState(false);
 
  useEffect(() => {
    const script = document.createElement("script");
    script.src = "https://app.lemonsqueezy.com/js/lemon.js";
    script.defer = true;
    script.onload = () => {
      setLemonLoaded(true);
    };
    document.body.appendChild(script);
 
    return () => {
      document.body.removeChild(script);
    };
  }, []);
 
  return (
    <>
      {lemonLoaded ? (
        <a
          href="https://[STORE].lemonsqueezy.com/checkout/buy/[VARIANT_ID]"
          className="lemonsqueezy-button"
        >
          Purchase my product
        </a>
      ) : (
        <p>Please wait...</p>
      )}
    </>
  );
}

In more recent versions of React you can use the <script> component. For more information, refer to the official React documentation for adding external script to a website.

Vue.js

In Vue.js, you can use the onMounted() lifecycle hook to load Lemon.js. This will ensure that Lemon.js is loaded only once when the component mounts.

<template>
  <div>
    <a
      v-if="lemonLoaded"
      href="https://[STORE].lemonsqueezy.com/checkout/buy/[VARIANT_ID]"
      class="lemonsqueezy-button"
    >
      Purchase my product
    </a>
    <p v-else>Please wait...</p>
  </div>
</template>
 
<script>
import { ref, onMounted } from "vue";
 
export default {
  name: "BuyButton",
  setup() {
    const lemonLoaded = ref(false);
 
    const loadScript = (src, onLoad) => {
      return new Promise((resolve, reject) => {
        const script = document.createElement("script");
        script.src = src;
        script.defer = true;
        script.onload = () => {
          onLoad();
          resolve();
        };
        script.onerror = reject;
        document.body.appendChild(script);
      });
    };
 
    onMounted(async () => {
      try {
        await loadScript("https://app.lemonsqueezy.com/js/lemon.js", () => {
          lemonLoaded.value = true;
        });
      } catch (error) {
        console.error("Failed to load the script:", error);
      }
    });
 
    return {
      lemonLoaded,
    };
  },
};
</script>

TypeScript

To enable code completion in TypeScript for Lemon.js, declare Lemon.js methods in a shims.d.ts file, ensuring TypeScript recognition.

interface Window {
  createLemonSqueezy: () => void
  LemonSqueezy: {
    /**
     * Initialises Lemon.js on your page.
     * @param options - An object with a single property, eventHandler, which is a function that will be called when Lemon.js emits an event.
     */
    Setup: (options: {
      eventHandler: (event: { event: string }) => void
    }) => void
    /**
     * Refreshes `lemonsqueezy-button` listeners on the page.
     */
    Refresh: () => void
 
    Url: {
      /**
       * Opens a given Lemon Squeezy URL, typically these are Checkout or Payment Details Update overlays.
       * @param url - The URL to open.
       */
      Open: (url: string) => void
 
      /**
       * Closes the current opened Lemon Squeezy overlay checkout window.
       */
      Close: () => void
    }
    Affiliate: {
      /**
       * Retrieve the affiliate tracking ID
       */
      GetID: () => string
 
      /**
       * Append the affiliate tracking parameter to the given URL
       * @param url - The URL to append the affiliate tracking parameter to.
       */
      Build: (url: string) => string
    }
  }
}

Re-initialize button listeners

Upon loading Lemon.js, this script automatically initializes and listens for .lemonsqueezy-button clicks.

However, you may encounter situations where Lemon.js initializes before your component has rendered. In such cases, manually call window.createLemonSqueezy() after the component has mounted and Lemon.js is loaded to retrigger button event listeners.

This method can be called multiple times as needed.

For example, in React:

useEffect(() => {
  window.createLemonSqueezy();
}, [])

Was this page helpful?