Docs
Next

Vanilla JS bundle

The listeners bundle for projects without React.

On this page

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, and it starts itself, so the markup and classes from the rest of these pages work without any code of yours.

Loading the bundleLink to this section

Add the script at the end of <body>:

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:

src/main.ts
import '@systhemaui/core/js'

What it doesLink to this section

FunctionStarts on loadBehaviour
initAos()yesAdds 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.
initParallax()yesMoves .parallax media against the scroll. See Parallax.
initScrollClasses()yesToggles scroll-on-top (page at the top) and is-scrolling-down (after 150px of downward scroll) on <body>.
initAccordion()yesA click on .accordion-title toggles its .accordion: data-state, data-expanded, and the title's aria-expanded and content's aria-hidden.
initHeader()yesA 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()yesRemoves no-transition from <body> on load, so transitions don't play while the page loads.
initCookieConsent()yesShows the cookie banner when window.__SYSTHEMA_COOKIE_CONSENT__.enabled is true. See below.

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:

<body class="no-transition">
@layer app {
  .no-transition,
  .no-transition * {
    transition: none !important;
  }
}

Content swapped in laterLink to this section

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:

window.SysthemaJS.addAnimationClasses()
window.SysthemaJS.updateParallax()

Differences from the React listenersLink to this section

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.

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.

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.