Skip to content
Docs

App blocks vs. Web Components

Every component can be placed two ways. They render the same component from the same data — the difference is who places it, how it’s configured, and where it’s allowed to go. (The one exception is the Quickview, which is web-component and JavaScript only — its trigger is your own markup, and it fetches its product itself, so it works on any page.)

  • App blocks — added through the theme editor. No code; you pick a component you built in the admin. The right choice for most merchants, and the only way to render inside product cards on collection pages.
  • Web Components — the <dkl-*> element written directly into your theme’s Liquid. Configured with data-* attributes and --dkl-* CSS. For developers customizing a theme by hand. (These are labelled “Web Components” on each component page.)
App block Web Component
Added by Theme editor (drag-and-drop) Hand-written in theme Liquid/HTML
Configuration A component, built in the admin data-* attributes, or a component by handle
Styling The component’s editor, with a live preview --dkl-* CSS styling tokens
Which discount Carried by the component A component by handle (data-component), or the data-discount-id attribute
Product cards / collection grids ✅ Supported ⚠️ Partial support — varies per component
Needs the app embed ✅ Yes ✅ Yes
No-flicker render ✅ Inline server render ✅ From a head carrier
Best for Merchants, no code Developers, full control

There is one app block for every component: Component. Its only setting is which component to render — a component you created and styled in the Shopify admin under Discount Kit → Components. See Components & the app block for that flow.

Online Store → Themes → Customize → (add block) → Component → pick your component

What an app block does for you:

  • Renders whichever component you picked — the component knows its own type, so the same block places a price, a picker, a table, a goal bar or a badge.
  • Resolves the eligible discount itself — the component carries the discount it was built for, and the block checks eligibility with the shared rules, so it agrees with the web-component path.
  • Carries all the styling — colours, spacing, typography, text and behaviour come from the component, emitted as a scoped <style> rule. You style it against a live preview in the admin rather than blind in the editor panel.
  • Only loads what it needs — the chosen component’s controller and nothing else.
  • Reaches contexts a tag can’t — most importantly product cards in a collection grid, where there’s no single product in <head> context to pre-stage a carrier from.

Use an app block when a merchant should be able to place the component without touching code, or whenever you need it inside a product card.

A web component is the <dkl-*> web component written straight into your theme’s markup:

<dkl-price></dkl-price>

By default, a web component needs zero attributes — the page’s primary product is the implicit default, and the tag clones a pre-staged carrier (markup, styling, and data-* values) before first paint. Configure it with data-* attributes and style it with --dkl-* CSS:

<dkl-price
data-show-savings="true"
style="--dkl-price-savings-background:#111; --dkl-price-savings-color:#fff"
></dkl-price>

What to know about web components:

  • Partial support off product pages. Product widgets (price, volume picker, volume table, sale badge) have carriers only where there’s a single product in context. A collection grid is paginated and per-product, so a hand-typed tag can’t be pre-staged there — use the app block for product cards. Tiered rewards belong to the whole cart, so its carriers are on every page: a tag works in a cart drawer, on the cart page or anywhere else.
  • Target a specific discount with a component (data-component="<handle>", which carries its discount) or with data-discount-id (the metaobject handle; the discount- prefix is optional). Place one tag per discount to show several.
  • Style with --dkl-* tokens in your own CSS, or name a component with data-component="<handle>" to reuse one you built in the admin. Without it the tag renders the built-in look; set the tokens on :root, the Custom CSS in Components → Styles, an inline style, or any ancestor. The defaults match the app block exactly, so an unstyled tag looks identical to an unstyled component.
  • Behaviour toggles may default off. For the volume picker, native-price update and quantity sync only run if you opt in (data-update-price-on-change="true" / data-sync-with-quantity="true"); any attribute you set wins over the carrier’s.

Use a web component when you’re editing the theme directly and want precise control over placement, attributes, and CSS.

Reach for an app block

The merchant should place it without code · you need it in a product card · you want styling managed in the admin, with a live preview.

Reach for a web component

You’re editing theme Liquid directly · you want exact control over placement and data-* · you’re styling with --dkl-* CSS · you need several discounts placed by hand. You can still point it at a component with data-component.