component-product-price Snippet
snippets/component-product-price.liquid renders a product's price block including regular price, sale price, compare-at price, unit price, and optional sale/sold-out badges. It supports volume pricing messaging, variant-based pricing, and currency code display. The component handles complex pricing scenarios including products with varying prices and quantity-based pricing breaks.
What It Does
- Renders product or variant prices with proper formatting.
- Displays regular and sale prices with compare-at price strikethrough.
- Shows unit pricing (price per unit of measurement).
- Supports volume pricing with price range display.
- Displays optional "Sale" and "Sold Out" badges.
- Handles currency code display when enabled.
- Provides accessible price labels for screen readers.
- Applies dynamic CSS classes based on price state.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
product | object | optional | Product object to render prices for. |
placeholder | boolean | optional | Render placeholder pricing when no product. |
use_variant | boolean | optional | Use selected/first variant instead of product-level pricing. |
show_badges | boolean | optional | Show "Sale" and "Sold Out" badges. |
price_class | string | optional | Extra CSS class to append to price wrapper. |
show_compare_at_price | boolean | optional | Show compare-at price when applicable (for volume pricing). |
Dependencies & Assets
| Type | Files / Components |
|---|---|
| CSS | External stylesheet (likely component-product-price.css) |
| JavaScript | None required |
| Shopify Filters | money, money_with_currency, money_without_currency |
| Data | Requires product object with pricing properties, settings.currency_code_enabled |
- No external JavaScript required - all functionality handled by Liquid.
- External CSS handles all price styling and badge display.
- Shopify money filters handle currency formatting.
Dynamic Styles
The snippet does not include inline styles. All styling is handled by external CSS files. However, the component uses dynamic CSS classes based on price state:
class="
price
{%- if price_class %} {{ price_class }}{% endif -%}
{%- if available == false %} price--sold-out{% endif -%}
{%- if compare_at_price > price and product.quantity_price_breaks_configured? != true %} price--on-sale{% endif -%}
{%- if compare_at_price > price and product.quantity_price_breaks_configured? %} volume-pricing--sale-badge{% endif -%}
{%- if product.price_varies == false and product.compare_at_price_varies %} price--no-compare{% endif -%}
{%- if show_badges %} price--show-badge{% endif -%}
"- Dynamic classes: Price wrapper classes change based on:
- Custom class (
price_classparameter) - Sold out state
- Sale state
- Volume pricing state
- Price variation state
- Badge display state
- Custom class (
Markup Structure
<div class="price [dynamic classes]">
<div class="price__container">
<div class="price__regular">
<!-- Regular price display -->
</div>
<div class="price__sale">
<!-- Sale price display -->
</div>
<small class="unit-price">
<!-- Unit price display -->
</small>
</div>
{%- if show_badges -%}
<!-- Sale and Sold Out badges -->
{%- endif -%}
</div>- Two price displays:
price__regularandprice__sale- CSS controls which is visible. - Unit price: Displayed in
<small>element when unit pricing available. - Badges: Optional sale and sold-out badges.
Regular Price Display
<div class="price__regular">
{%- if product.quantity_price_breaks_configured? -%}
<!-- Volume pricing range -->
{%- else -%}
<!-- Standard price -->
{%- endif -%}
</div>- Volume pricing: Shows price range when quantity breaks configured.
- Standard pricing: Shows single price otherwise.
Sale Price Display
<div class="price__sale">
{%- unless product.price_varies == false and product.compare_at_price_varies %}
<span>
<s class="price-item price-item--regular">
{{ compare_at_price | money }}
</s>
</span>
{%- endunless -%}
<span class="price-item price-item--sale price-item--last">
{{ money_price }}
</span>
</div>- Compare-at price: Strikethrough price shown when on sale.
- Sale price: Current sale price displayed.
- Conditional compare-at: Compare-at price hidden in certain variation scenarios.
Unit Price Display
<small class="unit-price caption{% if product.selected_or_first_available_variant.unit_price_measurement == nil %} hidden{% endif %}">
<span class="visually-hidden">{{ 'products.product.price.unit_price' | t }}</span>
<span class="price-item price-item--last">
<span>{{- product.selected_or_first_available_variant.unit_price | money -}}</span>
<span aria-hidden="true">/</span>
<span class="visually-hidden"> {{ 'accessibility.unit_price_separator' | t }} </span>
<span>
{%- if product.selected_or_first_available_variant.unit_price_measurement.reference_value != 1 -%}
{{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}}
{%- endif -%}
{{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
</span>
</span>
</small>- Conditional display: Hidden when unit pricing not available.
- Accessible format: Includes visually hidden labels and separator.
- Reference value: Shows measurement value if not 1 (e.g., "100" in "100ml").
Badges
{%- if show_badges -%}
<span class="badge price__badge-sale">
{{ 'products.product.on_sale' | t }}
</span>
<span class="badge price__badge-sold-out">
{{ 'products.product.sold_out' | t }}
</span>
{%- endif -%}- Sale badge: Shows "On Sale" text.
- Sold out badge: Shows "Sold Out" text.
- CSS control: CSS controls which badge is visible based on state.
Behavior
- Price calculation: Calculates prices based on product or variant (controlled by
use_variant). - Currency formatting: Formats prices using Shopify money filters.
- Currency code: Includes currency code when
settings.currency_code_enabledis true. - Price variation: Handles products with varying prices across variants.
- Volume pricing: Displays price range for quantity-based pricing.
- Sale detection: Detects sale state by comparing price to compare-at price.
- Badge visibility: CSS controls badge visibility based on sale/sold-out state.
- Accessibility: Includes visually hidden labels for screen readers.
Usage Example
Basic usage:
{% render 'component-product-price', product: product %}With variant pricing:
{% render 'component-product-price',
product: product,
use_variant: true
%}With badges:
{% render 'component-product-price',
product: product,
show_badges: true
%}With custom class:
{% render 'component-product-price',
product: product,
price_class: 'product-card__price'
%}Typically used in:
- Product pages (
sections/product.liquid) - Product cards (
snippets/component-product-card.liquid) - Collection pages
- Search results
- Any component displaying product pricing
Implementation Notes
Target selection: Component selects pricing target based on parameters:
use_variant: Usesproduct.selected_or_first_available_variantplaceholder: Usesnull(renders placeholder)- Otherwise: Uses
productobject
Price calculation: Prices calculated from target object:
compare_at_price: From target's compare-at priceprice: From target's price (defaults to 1999 if null)price_min/price_max: From product's price rangeavailable: From target's availability (defaults to false)
Currency formatting: Prices formatted using:
money: Standard money formatmoney_with_currency: Includes currency code (when enabled)money_without_currency: Currency code only (for structured data)
Currency code setting: Checks
settings.currency_code_enabledto determine format.Price variation handling: When
target == productandproduct.price_varies, uses translation with "from" prefix.Volume pricing: Detects
product.quantity_price_breaks_configured?to show price range instead of single price.Compare-at price display: Compare-at price shown when:
show_compare_at_priceis truecompare_at_priceexists- Not in certain variation scenarios
Price display logic: Two price divs (
price__regularandprice__sale) - CSS controls visibility based on sale state.Sale detection: Sale detected when
compare_at_price > price.CSS class system: Dynamic classes applied based on:
price--sold-out: When product unavailableprice--on-sale: When on sale (non-volume pricing)volume-pricing--sale-badge: When on sale with volume pricingprice--no-compare: When price doesn't vary but compare-at doesprice--show-badge: When badges enabled
Accessibility features:
visually-hiddenlabels for price typesvisually-hiddenseparator for unit pricearia-hidden="true"on decorative separator- Semantic HTML structure
Translation keys: Uses translation keys from
locales/en.default.json:products.product.price.regular_priceproducts.product.price.sale_priceproducts.product.price.unit_priceproducts.product.price.from_price_htmlproducts.product.volume_pricing.price_rangeproducts.product.on_saleproducts.product.sold_outaccessibility.unit_price_separator
Unit price calculation: Unit price calculated from variant's
unit_priceandunit_price_measurement.Unit price display: Unit price hidden when
unit_price_measurement == nil.Reference value: Unit price reference value only shown if not 1 (e.g., "100" in "$1.00 / 100ml").
Badge display: Badges only render when
show_badgesis true, but CSS controls which is visible.Placeholder support: Component can render placeholder pricing when
placeholderis true andtargetis null.Price item classes: Price elements use classes:
price-item: Base price item classprice-item--regular: Regular/compare-at priceprice-item--sale: Sale priceprice-item--last: Last price item in group
Strikethrough price: Compare-at price uses
<s>tag for strikethrough styling.Conditional rendering: Component only renders when
target != nullorplaceholder != null.Price range translation: Volume pricing uses translation with
minimumandmaximumvariables.From price translation: Varying prices use translation with
pricevariable for "from" prefix.Currency code conditional: Currency code included when
settings.currency_code_enabledis true.Price variation scenarios: Component handles complex scenarios:
- Price varies, compare-at varies
- Price doesn't vary, compare-at varies
- Price varies, compare-at doesn't vary
- Neither varies
Volume pricing compare-at: Compare-at price shown in volume pricing when
show_compare_at_priceis true.No compare-at in variations: Compare-at price hidden when
product.price_varies == false and product.compare_at_price_varies.Unit price measurement: Unit price uses variant's
unit_price_measurementfor reference value and unit.Badge CSS control: Badges always rendered but CSS controls visibility based on sale/sold-out state.
Sold out class:
price--sold-outclass applied whenavailable == false.Sale class logic: Sale class depends on volume pricing configuration:
price--on-sale: When not volume pricingvolume-pricing--sale-badge: When volume pricing
Price container: All price displays wrapped in
price__containerdiv.Regular price display: Regular price shown when not on sale or in volume pricing mode.
Sale price display: Sale price shown when on sale (compare-at > price).
Unit price positioning: Unit price displayed after regular/sale prices in
<small>element.Badge positioning: Badges displayed after price container.
Price formatting: All prices formatted using Shopify money filters for proper currency display.
Default price: Price defaults to 1999 (in cents) if target price is null.
Default availability: Availability defaults to false if target availability is null.
Money variable assignment: Prices converted to money format early for reuse.
Price min/max: Product price min/max used for volume pricing range.
Target comparison: Component compares
target == productto determine if using product-level pricing.Price varies check: Checks
product.price_variesto determine if prices differ across variants.Compare-at varies check: Checks
product.compare_at_price_variesfor compare-at price variation.Quantity breaks check: Checks
product.quantity_price_breaks_configured?for volume pricing.Unit price measurement check: Checks
unit_price_measurement == nilto hide unit price.Reference value check: Only shows reference value if not 1.
Currency code setting: Checks
settings.currency_code_enabledfor currency display.Translation interpolation: Uses translation variables for dynamic content:
from_price_html:pricevariablevolume_pricing.price_range:minimum,maximumvariables
Accessibility labels: All price types have visually hidden labels for screen readers.
Semantic HTML: Uses semantic elements (
<s>for strikethrough,<small>for unit price).