Campaign elements overview
Updated Oct 1, 20265 min read
On this page (8)
Hype Discounts renders its storefront campaign UI as custom elements — <hype-product-banner>, <hype-volume-selector> and the rest. The theme editor blocks place them for you. If your theme cannot use app blocks, or you want the element somewhere a block cannot reach, you can write the tag into Liquid yourself and pass it the campaign's App block ID.
The elements
| Element | Campaign type it serves | Theme block name | How it is placed |
|---|---|---|---|
<hype-product-banner> | Multi Products Discount, Order Discount | Hype: Product Banner | Section block, product page |
<hype-product-price> | Multi Products Discount, Order Discount | Hype: Product Price | Section block, product page |
<hype-free-gift-banner> | Gift with Purchase | Hype: Gift Banner | Section block, product page |
<hype-tiered-cart-progress-bar> | Cart Goals | Hype: Progress Bar | Section block, anywhere |
<hype-volume-selector> | Volume Discount | Hype: Volume Selector | Section block, inside the product form |
<hype-volume-table> | Volume Discount | Hype: Volume Table | Section block, product page |
<hype-announcement-bar> | Any | Hype: Announcement Bar | App embed, injected into <body> |
<hype-toast> | Any | Hype: Toast | App embed, injected into <body> |
<hype-free-gift-item> renders one gift row inside the gift banner and the progress bar. You never place it yourself, but you can style and read it — see Free gift banner.
The cart progress bar is a Hype Discounts campaign block. It is not part of Hype Cart Drawer, even when you place it beside the cart.
What loads them
All eight elements ship in one file, hype-ui.js, which the Hype: Discounts app embed loads on every page. Turn the embed on at Online Store → Themes → Customize → App embeds → Hype: Discounts before anything else. Without it, your custom tag stays an unknown element and renders nothing.
The embed also publishes window.HypeUIBlocksSchema: the settings you saved in the Hype admin, keyed by campaign ID. Each element reads its own entry from there.
Placing an element with custom code
- Open the campaign in Hype Discounts and go to its Blocks page.
- Click Add campaign block and pick the block type.
- In Step 1, tick I want to use it in my custom code.
- Click Copy next to App block ID.
- Paste that value into the element's
identifierattribute in your Liquid file. - Save the theme file, then finish the block's settings in Hype.
<hype-free-gift-banner identifier="{{ 'YOUR_APP_BLOCK_ID' }}" {% if request.design_mode %}design-mode="true"{% endif %}></hype-free-gift-banner>Ticking I want to use it in my custom code matters: it tells Hype to skip the theme check that otherwise looks for an app block carrying that ID and warns you when it finds none.
An element with no matching identifier renders nothing. Matching is exact, so a stray space at either end of the pasted value breaks it. <hype-announcement-bar> and <hype-toast> are the exceptions — they carry no identifier and take their content from attributes instead.
Common attributes
| Attribute | Applies to | Default | What it does |
|---|---|---|---|
identifier | The six placed elements | "" | Links the element to its block settings in window.HypeUIBlocksSchema |
design-mode | The six placed elements | false | design-mode="true" renders placeholder content so you can style the element in the theme editor with no live campaign |
Wrap design-mode in a request.design_mode check as shown above, so it only applies inside the theme editor.
identifier="admin-preview" is reserved. It puts the element into preview mode for the Hype admin, where the configuration is passed in as a property instead of read from the page. Do not use it on a storefront.
State attributes
<hype-free-gift-item> reflects its state onto itself, so you can style gifts from plain CSS or read them from JavaScript.
| Attribute | Present when |
|---|---|
is-added-to-cart | The gift is in the cart |
is-disabled | The gift cannot be claimed yet, or a claim is in flight |
is-loading | This gift's claim request is in flight |
hype-free-gift-item[is-added-to-cart] { opacity: 0.6; }hype-free-gift-item[is-disabled] { pointer-events: none; filter: grayscale(100%); }<hype-tiered-cart-progress-bar> reflects is-open, which tracks whether its body is expanded. It starts open; set is-open="false" to render it collapsed.
Styling
Every element renders into a shadow root, so your theme's CSS cannot reach inside it. Two supported hooks exist:
- CSS custom properties set on the element (or any ancestor) control colors, sizing and spacing. Each element accepts its own set; see its article.
::part()targets individual internal nodes for anything the variables do not cover.
Give the element an id and style that, so you do not affect other copies on the page:
#gift-banner-pdp { --header-bg-color: #1f2937; --border-radius: 4px;}#gift-banner-pdp::part(banner-claim-button) { text-transform: uppercase; letter-spacing: 0.04em;}The theme editor blocks write these variables for you from their settings fields, and each block also has Custom CSS and Custom JavaScript fields scoped to that block.
Some variables have unitless fallbacks, because the theme block always supplies the unit. When you place an element by hand, always write the unit yourself — --font-size: 14px, not --font-size: 14. The exceptions are <hype-volume-selector> and <hype-volume-table>, which take bare numbers for --font-size and --max-width.
Bundle and offer blocks, and the cart drawer, use a different styling system based on --hype-* variables. See Styling overview.
Elements created in JavaScript
The announcement bar and the toast are injected by their own app embeds when hype:campaigns-loaded fires, using the settings saved on the campaign. You can create either one yourself instead — they take all of their content from attributes:
document.addEventListener('hype:campaigns-loaded', (event) => { const blocks = window.HypeUIBlocksSchema[event.detail[0]?.campaignId] || [] const config = blocks.find((block) => block.type === 'announcement-bar') if (!config) return const bar = document.createElement('hype-announcement-bar') bar.setAttribute('message', config.settings.message) bar.setAttribute('icon-type', config.settings.icon.type) bar.setAttribute('icon-name', config.settings.icon.name) document.body.insertAdjacentElement('afterbegin', bar)})Turn the matching app embed off first, or you will get two bars.
Related
Was this article helpful?
Related articles
Still stuck?
Ask a follow-up and we'll see it came from “Campaign elements overview”.
Opens chat with your question and a link to this article.