Skip to main content Accessibility Feedback

Controlling the transition timing of show and hide methods with vanilla JavaScript

Over the last few days, we’ve created show() and hide() methods with vanilla JavaScript, added a transition animation, and added a fade-in animation.

The methods we wrote work great if you want to use the same animation timing every time. But what if you wanted to vary it? What if you wanted show content to reveal slowly, and other content to reveal fast?

Today, let’s look at how to adjust the animation timing.

Updating our CSS

Since we use CSS to control our animations, the first thing we need to do is add slow and fast animation options.

As a refresher, here’s our starting CSS.

.toggle-content {
    display: none;
    height: 0;
    opacity: 0;
    overflow: hidden;
    transition: height 350ms ease-in-out, opacity 750ms ease-in-out;
}

.toggle-content.is-visible {
    display: block;
    height: auto;
    opacity: 1;
}

We’ll add .show-fast and .show-flow classes to modify the default animations in our .toggle-content class.

.toggle-content {
	display: none;
	height: 0;
	opacity: 0;
	overflow: hidden;
	transition: height 350ms ease-in-out, opacity 750ms ease-in-out;
}

.show-fast {
	transition: height: 100ms ease-in-out, opacity 300ms ease-in-out;
}

.show-slow {
	transition: height: 2000ms ease-in-out, opacity 2500ms ease-in-out;
}

.toggle-content.is-visible {
	display: block;
	height: auto;
	opacity: 1;
}

Updating the HTML

We’ll modify our markup as well, adding our .show-fast or .show-slow classes as desired to control the animation speed.

<div class="toggle-content">
	This content reveals at normal speed.
</div>

<div class="toggle-content show-fast">
	This content reveals quickly.
</div>

<div class="toggle-content show-slow">
	This content reveals at slowly.
</div>

Here’s a demo.

Updating our JavaScript

You’ll notice in the demo that all three content areas reveal at the same speed.

We’ve adjusted our CSS, but our script is still assuming a 350ms transition time. We need a way to vary that by animation.

As a refresher, here’s our starting JavaScript.

// Show an element
var show = function (elem) {

	// Get the natural height of the element
	var getHeight = function () {
		elem.style.display = 'block'; // Make it visible
		var height = elem.scrollHeight + 'px'; // Get it's height
		elem.style.display = ''; //  Hide it again
		return height;
	};

	var height = getHeight(); // Get the natural height
	elem.classList.add('is-visible'); // Make the element visible
	elem.style.height = height; // Update the height

	// Once the transition is complete, remove the inline height so the content can scale responsively
	window.setTimeout(function () {
		elem.style.height = '';
	}, 350);

};

// Hide an element
var hide = function (elem) {

	// Give the element a height to change from
	elem.style.height = elem.scrollHeight + 'px';

	// Set the height back to 0
	window.setTimeout(function () {
		elem.style.height = '0';
	}, 1);

	// When the transition is complete, hide it
	window.setTimeout(function () {
		elem.classList.remove('is-visible');
	}, 350);

};

// Toggle element visibility
var toggle = function (elem, timing) {

	// If the element is visible, hide it
	if (elem.classList.contains('is-visible')) {
		hide(elem);
		return;
	}

	// Otherwise, show it
	show(elem);

};

Let’s look at two different ways to approach it.

Option 1: Pass in the timing as an argument

The easiest way to write (but the hardest to maintain) is to pass in the timing as an argument in our methods.

We’ll use a ternary operator to check if the timing variable is set. If it is, we’ll use it. If not, we’ll fallback to 350.

// Show an element
var show = function (elem, timing) {

	// Get the transition timing
	timing = timing ? timing : 350;

	// ...

	// Once the transition is complete, remove the inline max-height so the content can scale responsively
	window.setTimeout(function () {
		elem.style.height = '';
	}, timing);

};

// Hide an element
var hide = function (elem, timing) {

	// Get the transition timing
	timing = timing ? timing : 350;

	// ...

	// When the transition is complete, hide it
	window.setTimeout(function () {
		elem.classList.remove('is-visible');
	}, timing);

};

// Toggle element visibility
var toggle = function (elem, timing) {

	// If the element is visible, hide it
	if (elem.classList.contains('is-visible')) {
		hide(elem, timing);
		return;
	}

	// Otherwise, show it
	show(elem, timing);

};

Here’s a demo with the timing passed in as an argument.

Option 2: Detect the class

A more automatic approach is to detect if our content area has a .show-fast or .show-slow class on it and adjust our setTimeout() delay accordingly.

var timing = 350;
if (elem.classList.contains('show-fast')) {
	timing = 100;
}
if (elem.classList.contains('show-slow')) {
	timing = 2000;
}

// ...

// Once the transition is complete, remove the inline max-height so the content can scale responsively
window.setTimeout(function () {
	elem.style.height = '';
}, timing);

Since we use this in both the show() and hide() methods, let’s assign it to a helper function.

// Get the transition timing
var getTiming = function (elem) {
	var timing = 350;
	if (elem.classList.contains('show-fast')) {
		timing = 100;
	}
	if (elem.classList.contains('show-slow')) {
		timing = 2000;
	}
	return timing;
};

// Show an element
var show = function (elem) {

	// Get the transition timing
	var timing = getTiming(elem);

	// ...

	// Once the transition is complete, remove the inline height so the content can scale responsively
	window.setTimeout(function () {
		elem.style.height = '';
	}, timing);

};

// Hide an element
var hide = function (elem) {

	// Get the transition timing
	var timing = getTiming(elem);

	// ...

	// When the transition is complete, hide it
	window.setTimeout(function () {
		elem.classList.remove('is-visible');
	}, timing);

};

Here’s a demo using automatic class detection.