Add a Class to an Element on Scroll in WordPress

A common WordPress effect is to add a class to the header, a back to top button or any other element once the visitor has scrolled down a bit, and remove it again at the top of the page. CSS then does the rest: a smaller sticky header, a shadow, a button that fades in.

This snippet adds a class to an element on scroll after a set number of pixels. It is plain JavaScript, so it works on block themes and pages that do not load jQuery.

The snippet

(function () {
	var selector = '.element'; // Elements that get the class.
	var className = 'active'; // Class added after scrolling.
	var offset = 100; // Pixels to scroll before the class is added.

	var elements = document.querySelectorAll(selector);
	if (!elements.length) {
		return;
	}

	var ticking = false;

	function update() {
		var scrolled = window.scrollY > offset;
		elements.forEach(function (el) {
			el.classList.toggle(className, scrolled);
		});
		ticking = false;
	}

	window.addEventListener('scroll', function () {
		if (!ticking) {
			ticking = true;
			window.requestAnimationFrame(update);
		}
	}, { passive: true });

	update();
})();

Change the three values at the top: the CSS selector of the element, the class to add, and how many pixels to scroll first.

How it works

  • The script finds the elements once, then listens to the scroll event. When window.scrollY is larger than offset, every element gets the class; above it, the class is removed.
  • requestAnimationFrame runs the update at most once per frame, and the listener is passive, so scrolling stays smooth.
  • It also runs once on load, so a page that is opened halfway down (after a reload or a link to an anchor) gets the class right away.
  • The older version of this post used jQuery’s $. WordPress loads jQuery in noConflict mode, so $ is not defined there and the script stopped with an error. Block themes often do not load jQuery at all.

Add it with Scripts Organizer

In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Conditions and set Template to All (or only the pages that need it). Under Script location tick Footer, set Footer Mode to Javascript, paste the code and publish.

Scripts Organizer prints header and footer code with the Conditions trigger on the front end, not with Everywhere, and adds the <script> tag itself. The footer is the right place: the elements already exist when the script runs.

Example CSS

For a header that gets a background and a shadow once the page scrolls, with var selector = '.site-header';, add this to your theme’s stylesheet or a Scripts Organizer header block with Header Mode CSS:

.site-header {
	transition: box-shadow 0.3s ease, background-color 0.3s ease;
}

.site-header.active {
	background-color: #fff;
	box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
}

Customise it

  • Several elements: use a selector list, for example '.site-header, .back-to-top'.
  • Add the class to <body> instead: use 'body' as the selector and style children with body.active .site-header.
  • Toggle a class when an element itself scrolls into view: see Add and Remove a Class on Scroll in WordPress.

Gotchas

  • Elements added to the page later, for example by a popup or an AJAX filter, are not found. Move the querySelectorAll line into update() if you need them.
  • Animating height or padding on a sticky header can make the page jump. transform and box-shadow are cheaper to animate.

In the Scripts Organizer library Import it with one click from Scripts Organizer.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.