---
title: "Vanilla JS bundle"
description: "The listeners bundle for projects without React."
requested_language: sk
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/sk/next/styling/vanilla-js
version: unreleased (main)
docs_index: https://docs.systhema.app/sk/next/llms.txt
---
> This page isn't translated yet. Showing English.


HTML projects without React get Systhema's client-side behaviour from one script in `@systhemaui/core`: scroll reveals, parallax, scroll classes, the accordion, the header menu and the cookie consent banner. It is the plain-JavaScript counterpart of the React [listeners](https://docs.systhema.app/sk/next/components/listeners.md), and it starts itself, so the markup and classes from the rest of these pages work without any code of yours.

## Loading the bundle

Add the script at the end of `<body>`:

```html title="index.html"
<script src="node_modules/@systhemaui/core/dist/js/bundle.global.js" defer></script>
```

`bundle.global.js` is a minified IIFE (about 55 KB) that registers every listener when it loads and exposes the functions on `window.SysthemaJS`. Copy it into your public folder if your server doesn't serve `node_modules`.

With a bundler, import the ESM build instead. Importing it has the same effect, so a bare import is enough:

```ts title="src/main.ts"
import '@systhemaui/core/js'
```

## What it does

| Function                   | Starts on load | Behaviour                                                                                                                                                                                                  |
| -------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `initAos()`                | yes            | Adds `animated` to `.aos` / `.animates-on-scroll` elements as they scroll in, and removes it again below the fold unless they have `animates-once`. See [Animation](https://docs.systhema.app/sk/next/styling/animation.md).                       |
| `initParallax()`           | yes            | Moves `.parallax` media against the scroll. See [Parallax](https://docs.systhema.app/sk/next/styling/parallax.md).                                                                                                                                 |
| `initScrollClasses()`      | yes            | Toggles `scroll-on-top` (page at the top) and `is-scrolling-down` (after 150px of downward scroll) on `<body>`.                                                                                            |
| `initAccordion()`          | yes            | A click on `.accordion-title` toggles its `.accordion`: `data-state`, `data-expanded`, and the title's `aria-expanded` and content's `aria-hidden`.                                                        |
| `initHeader()`             | yes            | A click on `.header-navigation-menu-toggle` or `.menu-toggle` opens and closes `.menu` (`is-open`); the backdrop and in-menu links close it, and `button.menu-navigation-item` toggles its sub-navigation. |
| `initFixLoadTransitions()` | yes            | Removes `no-transition` from `<body>` on `load`, so transitions don't play while the page loads.                                                                                                           |
| `initCookieConsent()`      | yes            | Shows the cookie banner when `window.__SYSTHEMA_COOKIE_CONSENT__.enabled` is `true`. See [below](#cookie-consent).                                                                                         |

The accordion and header listeners use event delegation on `<body>`, so they work for markup added later. `addAnimationClasses()` and `updateParallax()` run one pass of the scroll-reveal and parallax engines by hand.

To suppress transitions until the page has loaded, start with the class on `<body>` and add the matching CSS:

```html
<body class="no-transition">
```

```css
@layer app {
  .no-transition,
  .no-transition * {
    transition: none !important;
  }
}
```

### Content swapped in later

The listeners pick up new markup on their own in most cases: the click handlers are delegated, and the scroll-reveal and parallax engines re-measure on every scroll. The bundle also listens for htmx's `htmx:afterSwap` event to re-check scroll reveals and reset the accordion and menu state. After any other kind of DOM swap, call the engines once:

```js
window.SysthemaJS.addAnimationClasses()
window.SysthemaJS.updateParallax()
```

## Differences from the React listeners

The bundle and the React listeners read the same classes, but the scroll-reveal engine is older and simpler:

- It measures on every `scroll`, `resize` and `touchmove` event instead of using an `IntersectionObserver`.
- On viewports 768px and wider, an element reveals when its vertical middle passes the bottom of the viewport; on narrower ones, when its top is 20px inside. The React `AosListener` reveals at 20px everywhere.
- An element re-arms as soon as its top is below the fold, without the React listener's extra margin.

Both honour `prefers-reduced-motion` the same way: the CSS snaps reveals to their end state, and `initParallax()` writes no transform and follows the preference live.

## Cookie consent

Set the configuration before the bundle loads. The banner code (`vanilla-cookieconsent`) is imported only when `enabled` is `true`, so a page without consent pays nothing beyond the bundle itself.

```html title="index.html"
<script>
  window.__SYSTHEMA_COOKIE_CONSENT__ = {
    enabled: true,
    policyLinks: [{ label: 'Privacy policy', url: '/privacy-policy' }],
  }
</script>
<script src="node_modules/@systhemaui/core/dist/js/bundle.global.js" defer></script>
```

A link to `#cookie-settings` reopens the preferences, and `theme` forces a color-system mode on the banner. The full option list is in [Cookie consent](https://docs.systhema.app/sk/next/guides/cookie-consent.md).

## Related

- [HTML template](https://docs.systhema.app/sk/next/getting-started/templates/html.md)
- [Listeners](https://docs.systhema.app/sk/next/components/listeners.md)
- [Cookie consent](https://docs.systhema.app/sk/next/guides/cookie-consent.md)
