Use theme buy button in my app block

Topic summary

A developer created an app feature enabling customers to add multiple product variants to cart with one click, but encountered compatibility issues with theme-specific buy button behaviors.

Core Problem:

  • Different themes handle cart submissions differently (cart drawer vs. page redirect)
  • Theme-specific callbacks and custom JavaScript aren’t accessible to app blocks
  • Product form IDs and section information aren’t passed to app blocks

Proposed Solutions:

  1. Allow merchants to configure custom form selectors in app settings
  2. Let merchants specify theme element IDs for dynamic adjustment

Working Solution (with limitations):

  • Merchants configure a form selector (default: 'form:has([name="id"]):has(button[type="submit"])')
  • Disable the standard name='id' input and inject variant items into the product form
  • Manually trigger button click via JavaScript
  • On ‘FormNotFound’ error, fall back to AJAX API and redirect to cart

Known Exceptions:

  • Dawn theme’s ‘Pop up’ cart expects single item payload, not array
  • Some themes require variant/quantity selector information from the form itself

The app is available on the Shopify App Store and works with most themes using this approach.

Summarized with AI on November 9. AI used: claude-sonnet-4-5-20250929.

Hi everyone,

I’ve developed a new app feature that allows customers to add multiple variants to their shopping cart with just one click.

This is quite simple to implement (see the code snippet below for a simplified example).

However, there’s a problem with this code: some merchants have theme-specific callbacks on their submit buttons. Some redirects to the cart page, while others open a cart drawer.

In most themes, there are ‘buy buttons’ blocks included. I’m wondering if it’s possible for merchants to use these blocks with my app feature without having to edit their theme code. Unfortunately, in the themes I’ve looked at, the section and product form ID information isn’t passed to app blocks, so I haven’t found a way to avoid having to create custom ‘Add to Cart’ buttons.

Is there any solution? Or the best I can do is allow user to add custom javascript?

Hi Infalodon,

This is a tricky issue as you found, there’s no way to completely ensure that the buy button will trigger a cart drawer or redirect to cart/ checkout. Theme developers could use different techniques to control this, and merchants could change their theme settings that would affect what call-back function is used - so there’s no “one-size-fits-all” approach possible here. What you could do is to create offer settings within your app’s configuration to allow merchants to specify the IDs of their theme’s form elements or any other relevant selectors. This way, your app could dynamically adjust to work with the merchant’s specific theme setup? Is this an app that will be on the Shopify App Store?

Thank your for your answer

Indeed, ask to merchant for form id would be a good solution, hoping it’s not a dynamic one. I would try it out!

This is a shopify app that’s already available on the Shopify App Qtore yes!

Best solution I’ve found is the following one:

  1. I allow merchants to configure a form selector. By default I use
'form:has([name="id"]):has(button[type="submit"])'
  1. Then, I disabled the name='id' input and inject variants into the product form
export interface ShopifyCartItem {
  id: string;
  quantity: number;
  properties?: { [key: string]: string };
}

  /**
   * Updates the product form with the given items.
   *  items - An array of ShopifyCartItem objects representing the items to update the form with.
   */
  public updateProductForm(items: ShopifyCartItem[]) {
    // Remove all previously injected elements and add the new ones
    this.form.querySelectorAll(`input.planet-dataset`).forEach((el) => {
      this.form.removeChild(el);
    });
    const inputId = this.form.querySelector(
      `input[name=id]`
    ) as HTMLInputElement;
    if (inputId) {
      inputId.setAttribute("disabled", "true");
    }

    items.forEach(({ id, quantity }, index) => {
      const existingIdInput = this.form.querySelector(
        `input[name="items[${index}]id"]`
      );
      const idInput = existingIdInput || document.createElement("input");
      idInput.setAttribute("type", "hidden");
      idInput.setAttribute(`name`, `items[${index}]id`);
      idInput.setAttribute(`value`, id.toString());
      idInput.setAttribute("class", "planet-dataset");
      if (!existingIdInput) {
        this.form.appendChild(idInput);
      }

      const existingQtyInput = this.form.querySelector(
        `input[name="items[${index}]quantity"]`
      );
      const qtyInput = existingQtyInput || document.createElement("input");
      qtyInput.setAttribute("type", "hidden");
      qtyInput.setAttribute(`name`, `items[${index}]quantity`);
      qtyInput.setAttribute(`value`, quantity.toString());
      qtyInput.setAttribute("class", "planet-dataset");
      if (!existingQtyInput) {
        this.form.appendChild(qtyInput);
      }
    });
  }
  1. Then, I manually click on the button using javascript.

Until now it has been working with a lot of themes with two known exceptions:

  1. it doesn’t work with the ‘Pop up’ cart of dawn themes because it expects a response from /cart/add with a payload of ‘id’ and quantity’, not an array of items, so it breaks.

  2. Some themes work by getting info of quantity and variant selector of the theme, no amtter what’s in the form.

For now, the only workaround I’ve found is set a weird form selector so it’s not found, and then I catch the ‘FormNotFound’ error and do as I was doing before: redirect to the cart after using the AJAX API.