JavaScript
Jellyfish is a CSS framework first. The bundled script (dist/js/jellyfish.min.js) powers the navbar, modals, theme toggle and font-size control, drives the accordion and responsive-table enhancements, and adds these general helpers. No inline handlers — everything is delegated, so it works under a CSP.
Cookies
jfSetCookie(name, value, days);
jfGetCookie(name); // → string
jfDestroyCookie(name);
Debouncing
jfDebounce(eventType, fn, timeout?, args?) attaches a debounced window listener — use it for scroll / resize work. timeout defaults to 300ms; if you omit it, args can take its place. fn is called with args spread as its arguments, not with the native event — read window state directly inside it if you need it.
// Default 300ms timeout
function onResize() {
console.log(window.innerWidth);
}
jfDebounce("resize", onResize);
// Custom timeout
function onScroll() {
console.log(window.scrollY);
}
jfDebounce("scroll", onScroll, 150);
// Skip the timeout (keeps the 300ms default), pass args instead — spread
// into the handler as its arguments, e.g. fn("nav") below
function logSection(label) {
console.log(label, window.scrollY);
}
jfDebounce("scroll", logSection, ["nav"]);
Theme
theme.js owns the .jf-dark / .jf-light class on <html>, stored in localStorage["jf-theme"] as "dark" / "light" / "system" (absent = hasn't chosen). A stored choice outranks the data-default-theme the site declares, which in turn outranks the OS. Wire-up and the pre-paint snippet are on Theme Colours.
JellyfishTheme.get(); // "dark" | "light" (resolved)
JellyfishTheme.set("dark"); // "dark" | "light" | "system"
JellyfishTheme.toggle();
Markup: [data-theme-toggle] toggles, [data-theme-set="dark|light|system"] sets a mode. A jfThemeChange event fires on <html> with detail.theme.
Accordions & modals
Both are native and need no script to work. The bundled JS only adds events and conveniences — see Accordions and Modals. All four events (jfAccordionOpened / Closed, jfModalOpened / Closed) also push to window.dataLayer when GTM is present.
Lazy-loading background images
For a CSS background-image (which has no native loading="lazy"), add .has-bg-img and a data-bg-img pointing at the full-size image. Set a small placeholder inline; jfLazyLoadBackgroundImage swaps in the real one via IntersectionObserver as it nears the viewport. For a normal <img>, use the native loading="lazy" instead.