npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@madj2k/fe-frontend-kit

v2.0.38

Published

Shared frontend utilities, menus and mixins for projects

Readme

@madj2k/fe-frontend-kit

Reusable frontend toolkit including SCSS mixins and menu components (JS/SCSS).

# Installation

npm install @madj2k/fe-frontend-kit

Requirements: For SCSS mixins: Bootstrap SCSS (your project needs to install bootstrap and include it in the build) For menu components: none

Contains

  • SASS mixins (using Bootstrap 5.3 functions/mixins)
  • Menu components (JS + SCSS), Bootstrap-independent
  • Several JS-Tools

Usage in your project

SCSS Mixins

@use '@madj2k/fe-frontend-kit' as *;

Or import individual mixins:

@use '@madj2k/fe-frontend-kit/sass/00_mixins/colors' as *;

Menu components (JS and SCSS):

Each menu component can be used separately.

JS components (JS and SCSS):

Each JS component can be used separately.

Flyout-Navigation

Usage

Integrate the CSS- and JS-file into your project. Make sure jQuery is included. Then init the menu with

import { Madj2kFlyoutMenu } from '@madj2k/fe-frontend-kit/menus/flyout-menu';
document.querySelectorAll('.js-flyout-toggle').forEach((el) => {
  new Madj2kFlyoutMenu(el, { animationDuration: 800 });
});

Optional for automatically closing of the flyout menu resizing the browser window:

import { Madj2kBetterResizeEvent } from '@madj2k/fe-frontend-kit/tools/better-resize-event';
document.addEventListener('madj2k-better-resize-event', () => {
    document.dispatchEvent(new CustomEvent('madj2k-flyoutmenu-close'));
});

CSS:

@use '@madj2k/fe-frontend-kit/menus/flyout-menu' as *;

Basic HTML

<div class="siteheader" id="siteheader">

    [...]

    <nav>
        <button class="js-flyout-toggle"
            aria-label="Open menu"
            aria-controls="nav-mobile"
            aria-haspopup="true"
            aria-expanded="false">
            <span class="icon-bars"></span>
        </button>
        <div class="flyout js-flyout"
             id="nav-mobile"
             data-position-ref="siteheader">
            <div class="flyout-container js-flyout-container">
                <div class="nav-mobile-inner js-flyout-inner">
                    CONTENT HERE
                </div>
            </div>
        </div>
    </nav>
</div>

IMPORTANT: If the siteheader is positioned with position:fixed and you are using full-height-mode (which is the default) you have to switch that to position:absolute when the menu is opened. Otherwise in the opened menu the scrolling won't work.

.flyout-open {
    .siteheader {
        position:absolute;
    }
}

Options Reference

State & Animation Classes

| Option | Type | Default | Description | |--------|------|---------|-------------| | openStatusClass | string | 'open' | Applied to trigger and menu when open. | | animationOpenStatusClass | string | 'opening' | Applied during opening animation. | | animationCloseStatusClass | string | 'closing' | Applied during closing animation. | | animationBodyClassPrefix | string | 'flyout' | Prefix for body animation classes like flyout-opening. | | openStatusBodyClass | string | 'flyout-open' | Applied to body when the flyout is open. | | openStatusBodyClassOverflow | string | 'flyout-open-overflow' | Applied when page height exceeds viewport (used in scroll-locking). |

CSS Class Selectors

| Option | Type | Default | Description | |------------------------|------|-----------------------|-----------------------------------------------------------------| | contentSectionClass | string | 'js-main-content' | Content wrapper used when creating no-scroll helper. | | menuClass | string | 'js-flyout' | Menu root element class. | | menuToggleClass | string | 'js-flyout-toggle' | Class for toggle buttons. | | menuCloseClass | string | 'js-flyout-close' | Class for close buttons inside the flyout. | | menuContainerClass | string | 'js-flyout-container' | Container used for slide animations (top transition). | | menuInnerClass | string | 'js-flyout-inner' | Inner content wrapper. Observed via ResizeObserver. | | heightCalculationClass | string | 'calculate' | Temporary class used during height determination. | | hoverParentClass | string | 'nav-main' | Class of main container of menu (used in eventMode: 'moueover'. |

Height & Size Behavior

| Option | Type | Default | Description | |--------|------|---------|-------------| | heightMode | 'full' | 'maxContent' | 'full' | Determines height behavior of the flyout. | | animationDuration | number | 500 | Animation duration in milliseconds. |

Padding & Layout Behavior

| Option | Type | Default | Description | |--------|------|---------|-------------| | paddingBehavior | number | 0 | Controls dynamic horizontal padding. | | paddingViewPortMinWidth | number | 0 | Minimum viewport width required before padding applies. | | scrollHelper | boolean | true | Creates additional wrapper structure to enable scroll-locking. |

Event Handling

| Option | Type | Default | Description | |--------|------|-------------| | eventMode | string | 'click' | Default event used for toggling the menu. Can be set to click or mouseover. |

Special: blur/gray effect for background

  • In order to achieve a blur/gray-effect for the background we add the following DIV to the main-content section:
<div class="background-blur"></div>

Then we deactivate the fullHeight of the flyout menu and make the blurry background clickable

import { Madj2kFlyoutdownMenu } from '@madj2k/fe-frontend-kit/menus/flyout-menu';
document.querySelectorAll('.js-flyout-toggle').forEach((el) => {
  new Madj2kFlyoutMenu(el, { fullHeight: false });
});
document.querySelector('.js-background-blur').addEventListener('click', function() {
    document.dispatchEvent(new CustomEvent('madj2k-flyoutmenu-close'));
});
  • And we need this additional CSS:
/**
 * background-blur for opened flyout
 */
.background-blur {
    position:fixed;
    top:0;
    left:0;
    width: 100%;
    height: 100%;
    backdrop-filter: blur(1px) grayscale(100%);
    background-color: rgba(255, 255, 255, 0.7);
    transition: opacity 0.3s ease-in-out;
    opacity:0;
    z-index:-1;
}

.flyout-open,
.flyout-closing {
    .background-blur {
        z-index:90;
    }
}

.flyout-open{
    .background-blur {
        opacity:1;
    }
 }

Pulldown-Navigation

Usage

Integrate the CSS- and JS-file into your project. Make sure jQuery is included. Then init the menu with

import { Madj2kPulldownMenu } from '@madj2k/fe-frontend-kit/menus/pulldown-menu';
document.querySelectorAll('.js-pulldown-toggle').forEach((el) => {
  new Madj2kPulldownMenu(el);
});

Optional for automatically closing of the flyout menu resizing the browser window:

import { Madj2kBetterResizeEvent } from '@madj2k/fe-frontend-kit/tools/better-resize-event';
document.addEventListener('madj2k-better-resize-event', () => {
    document.dispatchEvent(new CustomEvent('madj2k-pulldownmenu-close'));
});

CSS:

@use '@madj2k/fe-frontend-kit/menus/pulldown-menu' as *;

Basic HTML

<div class="siteheader">

    [...]

    <nav class="pulldown-wrap js-pulldown-wrap">
        <button class="pulldown-toggle js-pulldown-toggle"
           aria-label="Open Menu"
           aria-controls="nav-language"
           aria-haspopup="true"
           aria-expanded="false">
            <span>Menu-Item Level 1</span>
        </button>

        <div class="pulldown js-pulldown" id="nav-language">
            <div class="pulldown-inner">
                <ul>
                    <!-- used to have the right padding-top of the pulldown -->
                    <li class="pulldown-hide">
                        <a href="#" tabIndex="-1"><span>Menu-Item Level 1</span></a>
                    </li>
                    <li>
                        <a href="#"><span>Menu-Item I Level 2</span></a>
                    </li>
                    <li>
                        <a href="#"><span>Menu-Item II Level 2</span></a>
                    </li>
                    <li>
                        ...
                    </li>
                </ul>
            </div>
        </div>
    </nav>
</div>

Options Reference

State & Structural Classes

| Option | Type | Default | Description | |--------|------|---------|-------------| | openStatusClass | string | 'open' | Applied to menu, wrapper, and toggle when the pulldown is open. | | menuClass | string | 'js-pulldown' | Root class of the pulldown menu. Must match your HTML structure. | | menuToggleClass | string | 'js-pulldown-toggle' | Toggle buttons that control pulldown menus and also close others. | | menuWrapClass | string | 'js-pulldown-wrap' | Optional wrapper container that receives open/closed states. |

Animation & Timing

| Option | Type | Default | Description | |--------|------|---------|-------------| | animationDuration | number | 500 | Reserved for future open/close animation timing. Currently no CSS transition is applied by JavaScript. |

Internal Element References

These are automatically detected:

| Property | Description | |----------|-------------| | menu | The menu element referenced via aria-controls. | | menuWrap | Closest parent using menuWrapClass. | | toggleElement | The trigger element passed to the constructor. |

JS: Banner

A lightweight class to show a full-page overlay (banner, popup, hint or cookie layer), with opening and closing animation and optional cookie persistence.

Init:

import { Madj2kBanner } from '@madj2k/fe-frontend-kit/tools/banner';
const banner = new Madj2kBanner({
  bannerId: 'my-banner',
  activeClass: 'active',
  openClass: 'open',
  closingClass: 'closing',
  openingClass: 'opening',
  timeout: 1000,
  cookieName: 'myBannerCookie',
  cookieDays: 30,
  debug: false
});

HTML:

<div id="my-banner" class="banner my-banner">
  <div class="my-banner-content">
    <button class="my-banner-close" aria-controls="my-banner">Close</button>
    <p>Your overlay content here ...</p>
  </div>
</div>

CSS:

.my-banner {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  z-index: 9999;
}

JS: OWL-Thumbnails

A JavaScript helper class to create a main OWL carousel with a synchronized thumbnail navigation carousel.

Supports flexible configurations for both the main and the thumbnail carousels, including:

  • Custom navigation
  • Syncing main carousel to clicked thumbnails
  • Syncing thumbnails to main carousel changes
  • Optionally equalizing thumbnail heights
  • Optionally preventing the centered thumbnail stage shift (for designs where thumbs should stay left aligned)
  • Responsive and CMS-friendly (works with dynamic content)

This is especially useful for image galleries or product carousels in CMS setups (e.g. TYPO3, WordPress, etc.) where content may change dynamically.

Init with available options:

$('.js-slider-container').each(function () {
    const owlThumbnail = new Madj2kOwlThumbnail(
        '.js-main-carousel',
        '.js-thumbs-carousel',
        {
            main: {
              items: 1,
              margin: 20,
              dots: true,
              nav: true,
              autoHeight: true
            },
            thumbs: {
              items: 3,
              margin: 10,
              dots: false,
              nav: true,
              center: true
            },
            resizeEvent: 'custom.resize',
            equalizeThumbHeights: true,
            noStageOffset: true
        },
        false,
        this
    });
});

HTML:

<div class="js-main-carousel owl-carousel">
  <div class="item"><img src="image1.jpg" alt=""></div>
  <div class="item"><img src="image2.jpg" alt=""></div>
  <div class="item"><img src="image3.jpg" alt=""></div>
</div>
<div class="js-thumbs-carousel owl-carousel">
  <div class="item" data-index="0"><img src="thumb1.jpg" alt=""></div>
  <div class="item" data-index="1"><img src="thumb2.jpg" alt=""></div>
  <div class="item" data-index="2"><img src="thumb3.jpg" alt=""></div>
</div>

JS: Better Resize Event

A lightweight helper class that triggers a debounced 'madj2k-better-resize-event' event when the user finishes resizing the browser window.

It also manages a scrolling detection state (via body attribute) to avoid triggering resize-events during user scrolling on mobile, and respects active input fields (keyboard-issue on mobile).

Init with available options:

import { Madj2kBetterResizeEvent } from '@madj2k/fe-frontend-kit/tools/better-resize-event';
const betterResizeEvent = new Madj2kBetterResizeEvent({
    resizeEndTimeout: 300,
    scrollingEndTimeout: 600,
    viewportDeltaThreshold: 50
});

Usage:

document.addEventListener('madj2k-better-resize-event', () => {
  console.log('Resize fired');
});

JS: Scrolling

A lightweight scrolling helper class that enables:

  1. Body classes based on scroll direction (scroll-up / scroll-down)
  2. Smooth anchor scrolling with optional offset
  3. Automatic scrolling when collapsible elements (like Bootstrap .collapse) open
  4. Appear-on-scroll animations for elements

The class is fully configurable via options and is designed to be used in CMS contexts where elements can be added, removed or re-ordered dynamically.

Init with available options:

import { Madj2kScrolling } from '@madj2k/fe-frontend-kit/tools/scrolling';
const scrolling = new Madj2kScrolling({
    anchorScrolling: {
      selector: ['a[href^="#"]', 'a[href*="#"]'],
      offsetSelector: null,
      disableSelector: '.js-no-scroll',
      collapsibleSelector: ['.collapse'],
      behavior: 'smooth',
      scriptScrollTimeout: 800,
      timeout: 500,
      threshold: 40
    },
    appearOnScroll: {
      selector: ['.js-appear-on-scroll'],
      timeout: 500,
      threshold: 25
    },
    debug: false
});

Usage with Appear-On-Scroll (HTML):

<div class="js-appear-on-scroll">
  <h2>Animated content</h2>
  <p>This will fade and move in when scrolled into view.</p>
</div>

JS: Element In Viewport

A lightweight helper class that adds a configurable class to any DOM element once it becomes visible in the viewport. Perfect for triggering CSS-based animations (e.g., quote reveals, fade-ins, transitions) when an element enters view.

  • Works with IntersectionObserver API
  • Purely DOM-based (no keyframes required)
  • Fully configurable (threshold, delay, class)
  • Ideal for CMS-driven content (dynamic DOM)
  • Designed for performance and flexibility

Init:

document.querySelectorAll('.js-inview').forEach((el) => {
    new Madj2kElementInViewport(el, {
        visibleClass: 'is-in-viewport',
        threshold: 0.5,
        debug: false
    });
});

HTML-Example

<section class="my-element js-inview">
    <div class="my-element-content">Lorem ipsum dolor sit amet.</div>
</section>

SCSS-Example

.my-element {
    .my-element-content {
        opacity: 0;
        transform: translateY(20%);
        transition: opacity 0.6s ease, transform 0.6s ease;
    }

    &.is-in-viewport {
        .my-element-content {
            opacity: 1;
            transform: translateY(0);
        }
    }
}

JS: Toggled Overlay

This class toggles the visibility of any target element referenced by the aria-controls attribute of a trigger element (button, link, etc.). It manages ARIA attributes for accessibility and allows overlays to be closed externally via a custom event.

Init with available options:

import { Madj2kToggledOverlay } from '@madj2k/fe-frontend-kit/tools/toggled-overlay';
const overlayToggle = new Madj2kToggledOverlay('.js-toggled-overlay');

HTML:

<button class="js-toggled-overlay toggled-overlay-button"
        aria-label="Open overlay"
        aria-controls="my-overlay"
        aria-expanded="false">
  <span class="icon icon-info"></span>
</button>

<div id="my-overlay" class="toggled-overlay" aria-hidden="true">
  <!-- Overlay content -->
</div>

JS: Simple Fade Slider

A lightweight fade slider using opacity and z-index.

  • Purely DOM based (no keyframes required)
  • Automatic looping through an arbitrary number of slides
  • Fully accessible with aria-hidden management
  • Configurable via options
  • Designed for CMS contexts with dynamic content

Init with available options:

import { Madj2kSimpleFadeSlider } from '@madj2k/fe-frontend-kit/tools/simple-fade-slider';
document.querySelectorAll('.js-fade-slider').forEach((el) => {
    new Madj2kSimpleFadeSlider(el, {
        duration: 8,
        classSlide: 'fade-slider-item',
        classVisible: 'is-visible',
        debug: true
    });
});

HTML:

<section class="fade-slider js-fade-slider" aria-label="Image gallery">
    <div class="fade-slider-item">
        <img src="img1.jpg" alt="Description 1">
    </div>
    <div class="fade-slider-item">
        <img src="img2.jpg" alt="Description 2">
    </div>
    <div class="fade-slider-item">
        <img src="img3.jpg" alt="Description 3">
    </div>
</section>