Skip to main content

JavaScript and stylesheet tags

Themes have two ways to ship JavaScript and CSS: asset files included with the script_tag and stylesheet_tag filters, and code bundled inside sections with the {% javascript %} and {% stylesheet %} tags. Using each correctly keeps pages rendering fast; using them wrong silently blocks rendering. This guide covers both mechanisms and how to keep their payload small.

Choose the right mechanism

  • Theme-wide assets — a global stylesheet, a shared script — belong in the assets directory, included from your layout with stylesheet_tag or script_tag. If an asset is already included in the layout, don't include it again in a template or section.
  • Section-specific code belongs in the section file itself, inside {% stylesheet %} and {% javascript %} tags. The section stays self-contained and portable across themes, and pages that never render the section never pay for its code.

Use stylesheet_tag correctly

stylesheet_tag generates a standard <link rel="stylesheet"> tag:

{{ 'theme.css' | shoplaza_asset_url | stylesheet_tag }}
<link href="//static.shoplazza.com/themes/theme-589f053bba.css" rel="stylesheet" type="text/css" media="all" />

Note the media="all" in the output. media is a standard HTML attribute of the <link> tag that declares when the stylesheet applies: all is the default (always applies), screen means only when viewing on a screen, and print means only when the visitor prints the page or exports it to PDF.

The one thing stylesheet_tag lets you configure is this attribute's value — write it directly after the colon and it's placed into media as is:

{{ 'theme.css' | shoplaza_asset_url | stylesheet_tag: 'print' }}
<link href="//static.shoplazza.com/themes/theme-589f053bba.css" rel="stylesheet" type="text/css" media="print" />

This stylesheet now only applies when printing. Beyond being semantically correct, this has a performance benefit: when a stylesheet's media doesn't match the current context (a print stylesheet while browsing on screen), the browser downloads it at low priority and never blocks rendering on it — so the page paints sooner.

warning

Pass the value directly, as shown above. stylesheet_tag has no preload or other named options — the name: value form like stylesheet_tag: preload: true doesn't error; it stuffs the whole parameter into the media attribute and outputs a broken tag (media="Array").

Don't let scripts block rendering

script_tag always generates a parser-blocking tag — and it ignores any parameters, so there is no way to make it deferred:

<script src="//static.shoplazza.com/theme.js" type="text/javascript"></script>

A parser-blocking script stops the browser from building the page until the script is downloaded and executed, directly delaying first paint. Reserve script_tag for the rare script that genuinely must run before the page renders. For everything else, build the URL with shoplaza_asset_url and write the tag yourself:

<script src="{{ 'theme.js' | shoplaza_asset_url }}" defer></script>

Use defer when execution order matters (scripts run in document order after parsing), or async when it doesn't. Place scripts that can't be deferred at the end of body rather than in head.

Use the section tags for self-contained code

Inside a section, {% stylesheet %} content is injected just before the section's markup, and {% javascript %} content is injected before </body> — see section assets for the loading behavior.

Two practices keep them safe:

  • Wrap your JavaScript in a self-executing function. Variables stay inside a closure, and a runtime exception in one section can't break the others:

    {% javascript %}
    (function () {
    const el = document.querySelector('.product-detail');
    // ...
    })();
    {% endjavascript %}
  • Liquid works inside {% stylesheet %}, so theme settings can be referenced directly:

    {% stylesheet %}
    .promo-banner {
    background: {{ settings.color_btn_bg }};
    }
    {% endstylesheet %}

    Even so, keep global colors flowing through the CSS variables of your color system (background: var(--color-btn-bg)) rather than reading settings in every section — one source, consistent restyling.

Keep the payload small

  • Minify the JavaScript and CSS files you ship in assets.
  • Prefer CSS over JavaScript for visual behavior — transitions, toggles, and simple interactivity rarely need a script.
  • Avoid heavy libraries for small tasks; modern DOM APIs cover most theme needs, and every kilobyte ships to every visitor.
  • Split page-specific code into its own assets and include them only in the templates that use them, instead of bundling everything into one file loaded everywhere.