Skip to main content
dashboard.liquid tags are grouped by default vs optional usage.
  • Default components are already present in the shipped dashboard.liquid template.
  • Optional components can be added or used to replace parts of the default layout.
Common tags are documented on Common tags: {% legacy_navbar %}.

Default components

{% simple_next_billing_date_with_confirm %}

Inline editable next billing date control.
ParameterTypeDefault
show_labelBooleanfalse
{% simple_next_billing_date_with_confirm show_label: true %}
<span id="subscription_123_simple_next_billing_date_with_confirm">
  <span class="text-sm">Next order date</span>
  <span class="font-semibold">March 12, 2026</span>
</span>

{% simple_plan_switch_with_confirm %}

Inline plan switch select with confirmation modal.
ParameterTypeDefault
label_formatString ("frequency", "plan_name", "both")"frequency"
{% simple_plan_switch_with_confirm label_format: "plan_name" %}
<div id="subscription_123_simple_plan_switch_with_confirm">
  <select name="plan_switch[plan_id]">
    <option value="12" selected>Basic Plan</option>
    <option value="13">Premium Plan</option>
  </select>
</div>
Using label_format: "both" combines plan name and frequency:
<option value="12" selected>Basic Plan - Every 2 weeks</option>

{% manage_products %}

Primary CTA to manage existing products.
ParameterTypeDefault
sizeString ("small"/"large")"small"
button_textString"Manage products"
{% manage_products size: "small" %}
<div data-role="manage_products">
  <a id="sscv2_manage_products" href="/self-service/additions/edit" class="button">
    Manage products
  </a>
</div>

{% product_quantity_progress %}

Progress and status widget for plan-based product quantity rules. This component only renders when the active plan has a minimum and/or maximum product quantity configured.
The default dashboard.liquid already includes this tag, and you can move or add it elsewhere in the template.
ParameterTypeDefault
rail_background_colorString (CSS color)#E5E7EB
rail_fill_colorString (CSS color)nil (auto based on state)
ready_fill_colorString (CSS color)#16A34A
pending_fill_colorString (CSS color)#F59E0B
over_limit_fill_colorString (CSS color)#EF4444
Sample scenarios:
{% product_quantity_progress %}
{% product_quantity_progress rail_background_color: "#F3F4F6", ready_fill_color: "#16A34A", pending_fill_color: "#F59E0B", over_limit_fill_color: "#EF4444" %}
{% product_quantity_progress rail_background_color: "#E2E8F0", rail_fill_color: "#0EA5E9" %}
<div id="sscv2_product_quantity_progress" class="bg-white border rounded-xl p-6">
  <h2>Add 2 more items to receive your upcoming order</h2>
  <p>3 / 5+</p>
  <div class="h-4 rounded-full" style="background-color: #E5E7EB;">
    <div style="width: 60%; background-color: #F59E0B;"></div>
  </div>
</div>

{% product_listing %}

Main list of active ordered products.
ParameterTypeDefault
show_delete_buttonBooleantrue
show_quantity_selectorBooleantrue
show_swap_buttonBooleantrue
{% product_listing show_quantity_selector: false %}
<div id="sscv2_product_listing" class="divide-y">
  <div id="ordered_product_501_sscv2" class="py-6">
    <h3 class="font-medium">Protein Bar Box</h3>
    <p class="text-sm">Quantity: 2</p>
    <button type="button">Delete</button>
  </div>
</div>

{% next_order_price_overview %}

Core upcoming-order summary card.
ParameterTypeDefault
itemsString or Arrayrecurring_subtotal,one_time_subtotal,discount,shipping,total
show_discount_code_entryBooleantrue
{% next_order_price_overview items: "recurring_subtotal,shipping,total" show_discount_code_entry: false %}
<div id="subscription_123_next_order_price_overview" class="border rounded-xl p-6">
  <h3>Order summary</h3>
  <div class="flex justify-between"><span>Recurring subtotal</span><span>EUR 29.00</span></div>
  <div class="flex justify-between"><span>Shipping</span><span>Free</span></div>
  <div class="flex justify-between font-semibold"><span>Total</span><span>EUR 29.00</span></div>
</div>

{% add_product %}

Secondary CTA to browse catalog and add products.
ParameterTypeDefault
sizeString ("small"/"large")"large"
button_textString"Add product" (size: "large"), "Add products" (size: "small")
{% add_product size: "small" button_text: "Add meal" %}
<div data-role="add_product">
  <a id="sscv2_add_product" href="/self-service/additions/new" class="button">
    Add meal
  </a>
</div>

Optional components

{% latest_orders %}

Recent orders list.
ParameterTypeDefault
limitNumber3
{% latest_orders limit: 2 %}
<div id="sscv2_latest_orders">
  <article class="border rounded-xl p-4">
    <p class="text-xs">Jan 12, 2026 | Order #9876</p>
    <p class="text-sm font-semibold">2x Matcha Pods</p>
    <span class="pill pill--green">confirmed</span>
  </article>
</div>

{% next_order_preview %}

Upcoming order preview card.
{% next_order_preview %}
<div class="bg-white border rounded-xl p-4">
  <p class="text-sm font-semibold">Upcoming order</p>
  <p class="text-sm">Scheduled for March 12, 2026</p>
  <div class="flex justify-between mt-2">
    <span>2x Oat Drink</span>
    <span>EUR 14.00</span>
  </div>
</div>

{% product_listing_filtered %}

Filtered product list card (for segmented subscriptions).
ParameterTypeDefault
filter_byStringnil
filter_valueStringnil
titleStringnil
show_add_buttonBooleanfalse
add_button_textStringnil
show_manage_buttonBooleanfalse
manage_button_textStringnil
show_delete_buttonBooleantrue
show_quantity_selectorBooleantrue
show_swap_buttonBooleantrue
{% product_listing_filtered filter_by: "person" filter_value: "mom" title: "Menu for mom" show_manage_button: true %}
<section class="bg-white border rounded-xl p-4">
  <header class="flex justify-between items-center mb-4">
    <h2 class="text-lg font-semibold">Menu for mom</h2>
    <a id="sscv2_manage_products" href="/self-service/additions/edit">Manage products</a>
  </header>
  <div class="divide-y">
    <div class="py-4">1x Tomato Soup</div>
    <div class="py-4">2x Wholegrain Bread</div>
  </div>
</section>

Dynamic groups based on ordered product metadata

If your filter_value should adapt to subscriber-specific metadata (for example names like "Veronika" or "Michiel"), you can build the group list from subscription.ordered_products and then render product_listing_filtered in a loop.

How are dynamic values fetched?

You can do this directly in dashboard.liquid; no custom backend endpoint is required.
  • subscription.ordered_products is available in SSCv2 Liquid context.
  • Each ordered_product includes metadata.
  • Reading ordered_product.metadata.group gives the current subscription’s group value for that ordered product (or use ordered_product.metadata.person if your project still uses the legacy key).
  • Pass filter_by with the same metadata key (group or person) that produced the value.
  • Looping over ordered products lets you discover all group values present on the active subscription at render time.
So the template itself can fetch values for the current subscription and render sections dynamically. If you need a list of possible groups that are not yet present on the subscription (for example, a global project-wide list), that is not available from this template context alone and should be handled outside the template (for example by pre-populating metadata values via your own flows). In this pattern:
  • hardcoded sections stay explicit (Add-ons, Gifts, One-time extras)
  • dynamic sections include only metadata values currently present on the subscription
  • hardcoded values are excluded from the dynamic loop
  • exclusions and de-duplication are done case-insensitively (downcase)
{% assign excluded_groups_normalized = "add-ons|gifts|one-time extras" | split: "|" %}
{% assign seen_groups_normalized = "" %}

{% for ordered_product in subscription.ordered_products %}
  {% assign group_name = ordered_product.metadata.group | strip %}
  {% assign group_filter_key = "group" %}
  {% if group_name == blank %}
    {% assign group_name = ordered_product.metadata.person | strip %}
    {% assign group_filter_key = "person" %}
  {% endif %}
  {% assign normalized_group_name = group_name | strip | downcase %}

  {% if group_name != blank %}
    {% unless excluded_groups_normalized contains normalized_group_name %}
      {% capture marker %}|{{ normalized_group_name }}|{% endcapture %}

      {% unless seen_groups_normalized contains marker %}
        {% capture seen_groups_normalized %}{{ seen_groups_normalized }}{{ marker }}{% endcapture %}
        {% assign group_title = group_name | capitalize %}

        {% product_listing_filtered
        filter_by: group_filter_key,
        filter_value: group_name,
        title: group_title,
        show_add_button: true,
        show_manage_button: false,
        show_delete_button: false,
        show_quantity_selector: false,
        show_swap_button: false
      %}
      {% endunless %}
    {% endunless %}
  {% endif %}
{% endfor %}

{% product_listing_filtered filter_by: "group", filter_value: "Add-ons", title: "Add-ons", show_add_button: true, show_manage_button: false, show_delete_button: false, show_quantity_selector: false, show_swap_button: false %}
{% product_listing_filtered filter_by: "group", filter_value: "Gifts", title: "Gifts", show_add_button: true, show_manage_button: false, show_delete_button: false, show_quantity_selector: false, show_swap_button: false %}
{% product_listing_filtered filter_by: "group", filter_value: "One-time extras", title: "One-time extras", show_add_button: false, show_manage_button: false, show_delete_button: false, show_quantity_selector: false, show_swap_button: false %}
If your project stores group values under a different metadata key, replace ordered_product.metadata.group (and optional ordered_product.metadata.person fallback) with your key and pass that same key to filter_by.

{% next_shipment_date %}

Localized next shipment date text.
{% next_shipment_date %}
Next shipment on March 12, 2026

{% minimum_contract_duration %}

Commitment/contract duration block.
ParameterTypeDefault
variantString ("full", "label", "date")"full"
{% minimum_contract_duration variant: "label" %}
<span id="subscription_123_minimum_contract_duration_label">
  Committed until April 1, 2026
</span>

{% billing_and_shipping_breakdown %}

Billing interval breakdown text.
{% billing_and_shipping_breakdown %}
<span id="subscription_123_billing_and_shipping_breakdown">
  Monthly billing, weekly delivery
</span>