Skip to content

Anchors and cascade table

CardData-layer anchor / modeBehavior
Product pageauto_productMounts near product page ATC (system picks specific position)
Footerauto_above_footer / auto_below_footerTwo buttons within the card, choose one
Floating Iconsfloat_top / float_bottom / float_left / float_right4 edges within the card
Cart Drawerauto_cart_drawerMounts to cart drawer
Cart Pageauto_cartMounts to cart page
Custom Positionmode: "manual"Merchant places via manual block in theme editor
Product image overlayauto.anchor: "label"Product image overlay (Label widget)

Data layer = 9 MVP anchor values (5 sentinels + 4 float edges) + label, UI folded into 6 + 1 = 7 cards.

auto_* sentinels try DOM selectors in cascade order; the first match mounts:

AUTO_CASCADE_BY_ANCHOR = {
auto_product: ["below_add_to_cart", "below_price", "below_gallery"],
auto_cart: ["cart_top"],
auto_cart_drawer: ["drawer_top"],
auto_above_footer: ["above_footer"],
auto_below_footer: ["below_footer"],
auto_footer: ["footer_top"], // legacy, backward compat
}

Cascade order = “most stable Shopify platform feature” to “most theme-specific selector”. auto_product puts ATC first because form[action*="/cart/add"] is the most reliable cross-theme contract.

Float anchors don’t go through cascade — directly body child + position:fixed (self-contained surface).

Merchant-selectable: see “7 cards” above.

Internal cascade-only anchors (schema-legal, old widgets storing them still work, but editor UI doesn’t surface them):

Anchor keyMeaning
below_priceBelow price
below_add_to_cartBelow ATC button
below_galleryBelow product gallery
above_priceAbove price
above_add_to_cartAbove ATC button
below_titleBelow product title
above_titleAbove product title
below_descriptionBelow product description
cart_topCart top
drawer_topCart drawer top
above_footerAbove footer
footer_topFooter inner top (legacy)
below_footerBelow footer
float_top_left / float_top_right / float_bottom_left / float_bottom_rightFloat corner variants

Split into auto_above_footer + auto_below_footer on 2026-04-24. Old widgets storing auto_footer still work (mapped to footer_top cascade), but new widgets don’t emit this value.

5 paid themes have product form structures that normal cascade can’t align with Hoppy insertion points; hard-coded overrides apply:

schema_nameOverride behavior
Savor / Atelier (Shopify Horizon family)Mount after [class*="shopify-payment-button"]
BeyondAfter form’s 7th child = ATC block
MakerAfter form’s 8th child
EditionsAfter form’s 3rd child

Override target lookup is scoped to anchorNode.closest('form[action*="/cart/add"]') — no global document.querySelector fallback (prevents matching wrong elements).

When the merchant’s theme isn’t in the built-in 65-theme list, fill customAnchorSelectors in Display tab advanced section to override:

{
"product": ["#alt-buy-button-region"],
"productList": [],
"productMedia": [],
"exclude": [".competitor-badge"]
}
FieldPurpose
productProduct page widget mount location (highest priority, beats 65-theme defaults)
productListEach product card on collection / search / recommendation pages
productMediaImage / media slot inside product cards (overlay widget on image)
excludeBlock these scenes / exclude theme-native conflicting positions

Max 24 selectors per widget. Merchant-supplied selectors are merged into rules.js as virtual candidates with weight 50 (beats any hardcoded candidate).

The system bundles a ~65-theme DOM selector matrix (built via theme-probe live testing). Adding new themes requires probe-first observation, code-second.

Full theme list and per-theme behavior in source docs/theme-selectors.md.

Merchants can see the actual hit anchor in the Display tab StickyBar diagnostic panel — useful for debugging “widget didn’t appear at expected location”.

Diagnostic state writes to window.__TTB_DIAGNOSTICS__[widgetId] — also visible in browser console on storefront.