Navigation, payment icons & responsive requirements
Navigation - linklists
The platform exposes menus on the Liquid context as linklists[handle]. Your
theme must build the header nav from linklists['main-menu'].links and the
footer link columns from linklists['footer-menu'].links. These are the single
source of truth for what appears in the nav.
Both main-menu and footer-menu handles are platform-guaranteed to
resolve on every store - hardcode those two as your defaults.
{% for link in linklists['main-menu'].links %}
<a href="{{ link.url }}">{{ link.title }}</a>
{% if link.links.size > 0 %}
<ul class="dropdown">
{% for child in link.links %}
<li><a href="{{ child.url }}">{{ child.title }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}Each link: { title, url, type, resource, links[] }. Child links live on
link.links (not link.children).
Fallback
When linklists['main-menu'].links is empty (a fresh store), fall back to
auto-populated top-level collections:
{% assign nav_cols = collections | where: 'show_in_nav', true | where: 'parent_id', blank %}Do not
- Hardcode nav slots (
nav_link_1..Nsection settings). - Read
collection.parent_id/childrento build the nav (that mirrors the collection tree, not the merchant’s chosen menu). - Default to fictional strings like “Shop / New / Sale”.
The mobile drawer follows the same rule - iterate the same
linklists['main-menu'].links and render link.links indented or collapsible.
Do not ship a second menu source for mobile.
Payment icons - shop.enabled_payment_types
Render the payment-method row from the platform’s single source of truth for
what the store accepts, gated by one boolean setting show_payment_icons.
Either output the pre-rendered row:
{% if settings.show_payment_icons %}
{{ shop.payment_icons_html }}
{% endif %}or iterate shop.enabled_payment_types and render your own icon set. Never
hardcode a fixed <img src="visa.svg"> set or model it as a free-form
“show Visa / hide Amex” toggle divorced from the real accepted methods.
Safe links
Every link your theme ships in section defaults (header, footer, hero CTAs, collection tiles) must resolve for any store. Safe defaults:
/,/collections,/collections/all,/collections/all?sort_by=created-desc/search,/wishlist,/account/login,/cart/pages/<slug>URLs that fall through to the styled 404 when the merchant hasn’t created that page
The platform seeds four legal pages on every store, so these
/pages/<slug> URLs are also safe: /pages/about-us, /pages/privacy-policy,
/pages/terms-of-service, /pages/cookie-policy. The best way to surface them
is via linklists['footer-menu'] - they appear automatically.
Never ship defaults like /collections/best-sellers, /collections/sale,
/collections/men, /blogs/journal, or bare /about - those return a raw 404
for any store whose data doesn’t include them.
Responsive requirements
Every section must render correctly at 1440 / 768 / 375 px. Desktop-only themes are not shippable.
- Header collapses to a drawer on mobile.
- Multi-column grids reflow to 1-2 columns.
- The filter sidebar becomes a slide-in drawer on mobile.
- Sticky PDP info columns unstick / restack gracefully.
- Touch targets stay >= 44px.
Hard prohibitions:
- No
display: noneon mobile to hide a section the merchant configured - render it in a mobile-appropriate layout. - No hardcoded
width: 1440pxcontainers - usemax-width+ percentages. - No fixed-pixel font sizes that overflow at 375 px.
Empty & error states
Render styled HTML (never raw JSON or the browser default) for: empty cart,
empty wishlist, empty search, empty collection, and the 404 page
(templates/404.json must exist).