# JavaScript and stylesheet tags

> When a Shoplazza Theme should ship code as an asset file with script_tag and stylesheet_tag, when to bundle it in a section, and how to avoid blocking rendering.

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`](/docs/theme/references/liquid/filters/html#stylesheet_tag) or [`script_tag`](/docs/theme/references/liquid/filters/html#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](/docs/theme/references/liquid/tags/theme-tags#javascript). 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:

```liquid
{{ 'theme.css' | shoplaza_asset_url | stylesheet_tag }}
```

```html title="Output"
<link href="//static.shoplazza.com/themes/theme-589f053bba.css" rel="stylesheet" type="text/css" media="all" />
```

Note the `media="all"` in the output. [`media`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#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:

```liquid
{{ 'theme.css' | shoplaza_asset_url | stylesheet_tag: 'print' }}
```

```html title="Output"
<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:

```html
<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:

```liquid
<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](/docs/theme/architecture/sections/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:

  ```liquid
  {% javascript %}
    (function () {
      const el = document.querySelector('.product-detail');
      // ...
    })();
  {% endjavascript %}
  ```

- **Liquid works inside `{% stylesheet %}`**, so theme settings can be referenced directly:

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

  Even so, keep global colors flowing through the [CSS variables of your color system](/docs/theme/best-practices/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.
