Overview
Horizon includes two main button snippets for different use cases:
- button.liquid - Styled link buttons for navigation
- add-to-cart-button.liquid - Product add to cart functionality
Button (Link)
File Location: snippets/button.liquid
Renders a styled link element that looks like a button. Used for navigation and CTAs throughout the theme.
Parameters
URL to link to. If blank, renders a disabled link with aria-disabled="true".
Block object containing settings for label, style, and behavior.Required Settings:
label - Button text
style_class - Button style class
open_in_new_tab - Whether to open in new tab
Usage
Basic Example
{% render 'button', link: '/collections/all' %}
Complete Block Example
{% render 'button', link: block.settings.link %}
{% schema %}
{
"name": "Button",
"settings": [
{
"type": "text",
"id": "label",
"label": "Label",
"default": "Shop Now"
},
{
"type": "url",
"id": "link",
"label": "Link"
},
{
"type": "checkbox",
"id": "open_in_new_tab",
"label": "Open in new tab",
"default": false
},
{
"type": "select",
"id": "style_class",
"label": "Style",
"options": [
{ "value": "button", "label": "Primary" },
{ "value": "button-secondary", "label": "Secondary" },
{ "value": "link", "label": "Link" }
],
"default": "button"
}
]
}
{% endschema %}
Button Styles
The snippet supports three button styles via block.settings.style_class:
{%- assign block.settings.style_class = "button" -%}
{% render 'button', link: '/collections/all' %}
<!-- Renders as -->
<a href="/collections/all" class="button">
Shop Now
</a>
Open in New Tab
When block.settings.open_in_new_tab is enabled:
<a
href="{{ link }}"
{%- if block_settings.open_in_new_tab -%}
target="_blank"
rel="noopener noreferrer"
{%- endif -%}
>
{{ block_settings.label }}
</a>
The rel="noopener noreferrer" attribute is included for security when opening links in new tabs.
Disabled State
When link is blank, the button renders in a disabled state:
<a
{% if link == blank %}
role="link"
aria-disabled="true"
{% else %}
href="{{ link }}"
{% endif %}
>
{{ block_settings.label }}
</a>
Styling
The snippet includes scoped styles for link buttons:
button.liquid (stylesheet)
.link {
text-decoration: none;
text-decoration-color: currentcolor;
&:hover {
color: var(--color-primary-hover);
text-decoration-color: transparent;
}
}
Add to Cart Button
File Location: snippets/add-to-cart-button.liquid
Renders an “Add to Cart” button with dynamic states, animations, and visual feedback.
Parameters
Whether the product can be added to the cart. When false, button is disabled.
Custom button text. Falls back to translation 'actions.add_to_cart'.
The product object to be added to the cart.
If true, only shows the cart icon on mobile devices (hides text).Default: false
Additional CSS classes to apply to the button.
The ID attribute for the button element.
Testing identifier for automated tests.
Usage
Basic Example
{% render 'add-to-cart-button',
can_add_to_cart: product.available,
product: product
%}
Complete Product Form Example
blocks/add-to-cart.liquid
{% liquid
assign class = 'add-to-cart-button ' | append: block.settings.style_class
assign id = 'BuyButtons-ProductSubmitButton-' | append: block.id
%}
<span
{{ block.shopify_attributes }}
style="--add-to-cart-font-case: {{ settings.button_text_case }};"
>
{% render 'add-to-cart-button',
id: id,
class: class,
can_add_to_cart: can_add_to_cart,
product: closest.product,
add_to_cart_text: add_to_cart_text,
data_testid: 'standalone-add-to-cart'
%}
</span>
With Custom Text
{% render 'add-to-cart-button',
can_add_to_cart: product.available,
product: product,
add_to_cart_text: 'Buy Now',
class: 'button-large'
%}
Icon Only on Mobile
{% render 'add-to-cart-button',
can_add_to_cart: product.available,
product: product,
icon_only_on_mobile: true,
class: 'quick-add-button'
%}
Button States
The button supports multiple visual states:
{% render 'add-to-cart-button',
can_add_to_cart: true,
product: product
%}
Shows cart icon + text, fully interactive.
{% render 'add-to-cart-button',
can_add_to_cart: false,
product: product,
add_to_cart_text: 'Sold Out'
%}
Button is disabled, no icon shown.<button type="submit" disabled>
<span class="add-to-cart-text__content">
Sold Out
</span>
</button>
Shows checkmark burst animation after successful add to cart:<span class="add-to-cart__added">
<span class="svg-wrapper add-to-cart__added-icon">
{{- 'icon-checkmark-burst.svg' | inline_asset_content -}}
</span>
</span>
Triggered by JavaScript on successful cart addition.
Add to Cart Animations
The button supports different animation styles via settings.add_to_cart_animation:
add-to-cart-button.liquid
<add-to-cart-component
ref="addToCartButtonContainer"
data-product-variant-media="{{ product_variant_media }}"
data-add-to-cart-animation="{{ settings.add_to_cart_animation }}"
>
<!-- button markup -->
</add-to-cart-component>
Animation Types:
- Checkmark burst (default)
- Product image fly-to-cart
- Ripple effect
Product Variant Media
The snippet automatically determines the correct variant image:
add-to-cart-button.liquid
{%- liquid
assign product_variant_media = product.selected_or_first_available_variant.featured_media.preview_image | image_url: width: 100
if product.selected_or_first_available_variant.featured_media.preview_image == blank
assign product_variant_media = product.featured_media.preview_image | image_url: width: 100
endif
-%}
<add-to-cart-component
data-product-variant-media="{{ product_variant_media }}"
>
This image is used for cart animations.
Icon Only Mobile
Hides text on mobile when icon_only_on_mobile is true:
add-to-cart-button.liquid
<span class="add-to-cart-text__content{% if icon_only_on_mobile %} is-visually-hidden-mobile{% endif %}">
<span>
<span>
{{- add_to_cart_text | default: default_add_to_cart_text -}}
</span>
</span>
</span>
Useful for compact layouts like product cards or quick add buttons.
Button Markup
Complete button structure:
<add-to-cart-component
ref="addToCartButtonContainer"
data-product-variant-media="..."
data-add-to-cart-animation="..."
>
<button
id="{{ id }}"
type="submit"
name="add"
ref="addToCartButton"
on:click="/handleClick"
class="button {{ class }}"
data-testid="{{ data_testid }}"
>
<span class="add-to-cart-text">
<span class="svg-wrapper add-to-cart-icon">
<!-- Cart icon SVG -->
</span>
<span class="add-to-cart-text__content">
Add to Cart
</span>
</span>
<span class="add-to-cart__added">
<span class="svg-wrapper add-to-cart__added-icon">
<!-- Checkmark burst SVG -->
</span>
</span>
</button>
</add-to-cart-component>
JavaScript Events
The button emits events for cart updates:
button.on('click', '/handleClick')
Handled by the add-to-cart-component web component.
Accessibility
Uses proper <button type="submit"> element with name="add" for form submission.
<button disabled>
Sold Out
</button>
Properly disabled when product unavailable.
Text remains accessible to screen readers even when hidden on mobile:<span class="is-visually-hidden-mobile">
Add to Cart
</span>
Examples
<product-form>
<form method="post" action="/cart/add">
<!-- Variant selector -->
{% render 'add-to-cart-button',
can_add_to_cart: product.available,
product: product,
add_to_cart_text: 'Add to Cart',
class: 'button-primary'
%}
</form>
</product-form>
Block Schema Settings
When used in blocks, common settings include:
{
"type": "add-to-cart",
"name": "Add to Cart",
"settings": [
{
"type": "select",
"id": "style_class",
"label": "Style",
"options": [
{ "value": "button", "label": "Primary" },
{ "value": "button-secondary", "label": "Secondary" }
],
"default": "button-secondary"
}
]
}
Related Snippets
quick-add.liquid - Quick add modal functionality
- Cart Summary - Cart totals and checkout
quantity-selector.liquid - Product quantity input