Hype Bundles

Custom CSS and custom JavaScript

Updated Sep 10, 20265 min read

There are three places to put your own CSS or JavaScript, and which app you are in decides which of them exist.

WhereAppReachesHolds
The Hype theme app embed's settingsHype Discounts, Hype BundlesEvery page the embed loads onCustom CSS, Custom JS
An offer's Advanced sectionHype Discounts, Hype BundlesThat one offer's blockCustom CSS
The cart editor's Advanced panelHype Cart DrawerEvery page the drawer loads onCustom CSS, Custom JavaScript

The Hype: Cart Drawer app embed has no CSS or JavaScript settings of its own — only the API Proxy link. Everything for the drawer is configured in the app.

The theme app embed (Discounts and Bundles)

  1. Open Online Store → Themes → Customize.
  2. Open App embeds in the left sidebar.
  3. Expand Hype.
  4. Fill in Custom CSS or Custom JS.
  5. Click Save.

Custom CSS is emitted as a <style> element and Custom JS as a <script> element, both in the page, on every page the embed runs on. They load with the rest of the embed, so they are in place before the blocks mount.

Individual Hype blocks you add in the theme editor have their own Custom CSS and Custom JS boxes, scoped to that block.

An offer's Advanced section (Discounts and Bundles)

Each offer's Advanced section — collapsed, under Design on the first step — shows the block's unique class and takes CSS for that offer alone. It is injected into the page's <head> as a <style data-hype-custom-css="…"> element and re-applied whenever the block mounts, so an edited stylesheet replaces the previous one rather than stacking on it.

  • The limit is 20,000 characters.
  • The CSS cannot contain a closing </style> tag; it would end the injected element early. Saving is blocked if it does.
  • The class is hype-bundle-<id> or hype-offer-<id>. The id exists only after the first save, so the class appears from then on.
  • The wizard's live preview injects the same CSS the same way as you type it. The storefront gets it on save.

There is no per-offer custom JavaScript. Use the app embed's Custom JS for that.

The cart editor's Advanced panel (Cart Drawer)

Open the cart in the app, then the Advanced panel. It holds Custom CSS and Custom JavaScript, along with Extra cart trigger selectors and Extra native drawer selectors.

Both ride inside the drawer's published configuration rather than being written into the theme, so a literal </script> or </style> in your code is harmless. On the storefront the CSS becomes a <style id="hype-cd-custom-css"> in <head> and the JavaScript a <script id="hype-cd-custom-js"> at the end of <body>. Each is added once per page, keyed by that id: the drawer relocates itself in the document as it boots, and re-adding the script each time would run it more than once.

Because both are added only when the drawer boots, they run only on pages where an active cart is published.

The Custom HTML section's 16,000-character limit (Cart Drawer)

The cart drawer's Custom HTML section renders your markup raw — inline <style> and <script> included. It is the only drawer section that does. Its content is capped at 16,000 characters; over that, the editor refuses to save and reports how many characters you used.

Each block of markup runs its scripts once per page, keyed by the section and the content. Editing the HTML gives it a new key, so the new version runs; re-opening the drawer does not re-run the old one.

Why scripts do not run in the admin preview

The editor's preview renders your Custom HTML inside the Shopify admin, on Hype's own origin rather than your store's. Running merchant JavaScript there would execute store code in the admin, so script execution is switched off for the preview and any <script> in the markup is removed before it renders.

The consequence: the preview shows your layout but never runs your code. Anything script-driven — a reviews widget, a size chart, a chat launcher — will look empty or unstyled in the preview and work on the storefront. Always confirm on a real product or cart page before deciding something is broken.

Why third-party embeds cannot find their own element

Most third-party snippets look for a placeholder with document.querySelector('#their-widget') and then write into it. Inside the cart drawer, that lookup fails.

The drawer and the offer blocks are custom elements that render inside a shadow root. document.querySelector searches the page's document only; it does not cross a shadow boundary. So a widget script loaded on the page runs, finds nothing, and quietly does nothing — no error in the console, just an empty space where the widget should be.

The same limit applies to CSS: a page-level rule such as .hype-block .card { … } matches nothing inside a block. Custom properties are the exception — they inherit through the shadow boundary, which is why every Hype variable can be set from ordinary theme CSS.

What does work:

  • Style through the contract. Set --hype-* and --hype-cd-* variables, and use ::part() for the named internals.
  • Put third-party widgets outside the drawer. Place them in a theme section, and use the drawer only for the content you author.
  • Reach in from your own script with document.querySelector('hype-cart-drawer')?.shadowRoot, accepting that anything you find there other than a documented part may change in a future release.

Related articles

Still need help?

Start a chat and we'll pick it up right here.