htmx-ext-shopify gives you access to the Shopify Ajax API from HTML to progressively enhance your Liquid templates. It's an unofficial, experimental extension for htmx.
The extension manipulates API requests and responses in order to replace / update Liquid sections on the current page. The new HTML for sections comes from Bundled section rendering and inserted using htmx swapping and out of band swaps.
This behavior is controlled using existing and new (see below) hx-*
attributes on the form triggering the request.
Update the customer's cart through the Shopify Ajax API and update the current page in response.
htmx must be loaded before htmx-ext-shopify is loaded. It's currently tested with htmx v1.7.0.
You can simply vendor both htmx.min.js and htmx-ext-shopify.js by adding them to the assets/
folder in your Shopify Liquid theme. Then add <script>
tags for both to your theme's layout file, usually layout/theme.liquid
.
<script ...other js files for your theme <script src="{{ 'htmx.min.js' | asset_url }}" defer></script> <script src="{{ 'htmx-ext-shopify.js' | asset_url }}" defer></script>
hx-swap-section
The id of the Liquid section that shall be requested and used for swapping.hx-oob-sections
Comma-separated list of ids of Liquid sections that shall be requested and used for out of band swaps.- In urls from
hx-post
,hx-get
,… the string/{locale}/
is automatically replaced with the locale-aware root.
- My form is not handled by htmx.
- Make sure your attributes are set correctly.
- If the form is inserted by JS into the DOM you might have to call
htmx.process(el)
.
- My form / section disappears after submit but no replacement is inserted.
- Make sure the section id in
hx-swap-section
is correct. - Bundled section rendering doesn't work when accessing the theme on 127.0.0.1 through the Shopify CLI development server for some reason. Use the theme preview mode on the proper store domain instead.
- Make sure the section id in
Lets build an add to cart form for products that will replace itself with a success message instead of navigating to the cart page.
- Create a new section file
sections/ex-product-add.liquid
in your theme source. As a baseline copy the following code.
{%- liquid
assign variant = product.selected_or_first_available_variant
-%}
<h3>Add this product!</h3>
<form
action="{{ routes.cart_add_url }}"
method="post"
>
<input name="items[0][id]" value="{{ variant.id }}" hidden>
<label for="ex-quantity">QTY</label>
<input id="ex-quantity" name="items[0][quantity]" type="number" value="1">
<button type="submit">Add to cart</button>
</form>
{% schema %}
{
"name": "Example Product Add",
"settings": [],
"presets": [{
"name": "Example Product Add"
}],
"templates": [
"product"
]
}
{% endschema %}
-
Add the section to your product page. If your theme is using JSON templates you can do it through the theme editor. Otherwise add
{% section 'ex-product-add' %}
to yourtemplates/product.liquid
file. -
Test the form on a product page. Clicking the "Add to cart" should redirect to the cart page and the entered quantity should be in there.
-
Install htmx and htmx-ext-shopify as explained above.
-
Reference the extension in the form tag and declare that htmx should POST the form to the add to cart Ajax API.
…
<form
action="{{ routes.cart_add_url }}"
method="post"
hx-ext="shopify"
hx-post="/{locale}/cart/add.js"
>
…
The form will just disappear now after submitting instead of navigating. You can check that the item is still added to the cart though.
- Define the replacement for the form after submit. Create a new file
sections/ex-product-add-success.liquid
with the following content.
<h3>Product added!</h3>
<p><a href="{{ routes.cart_url }}">Go to cart</a></p>
Also update the form attributes in sections/ex-product-add.liquid
.
<form
action="{{ routes.cart_add_url }}"
method="post"
hx-ext="shopify"
hx-post="/{locale}/cart/add.js"
hx-swap-section="ex-product-add-success"
hx-target="#shopify-section-{{ section.id }}"
hx-swap="outerHTML show:top"
>
Submitting will now request the HTML for the ex-product-add-success
section with the API call.
Note that we also defined hx-target
and hx-swap="outerHTML …"
so the entire ex-product-add
section is replaced. The default behavior would be to replace the innerHTML of the form with the success HTML.
- Update sections with cart item counters etc. on the current page. Update the form tag by adding the
hx-oob-sections
attribute.
<form
action="{{ routes.cart_add_url }}"
method="post"
hx-ext="shopify"
hx-post="/{locale}/cart/add.js"
hx-swap-section="ex-product-add-success"
hx-target="#shopify-section-{{ section.id }}"
hx-swap="outerHTML show:top"
hx-oob-sections="announcement-bar,cart"
>
The section ids for this attribute depend on your theme. Look for HTML id
attributes that start with shopify-section-
on parents of elements that need to update.
You can copy the complete examples from the files below