jQuery became popular partly because it made simple animation easy. Fading in a message or sliding open a panel takes one method call, with sensible defaults. These built-in methods are called jQuery effects. This lesson covers the common ones, how to time and chain them, and when plain CSS is the better tool.
Show, hide and toggle
.hide() sets display: none, .show() brings the element back with its original display value, and .toggle() switches between the two. Called with no arguments they act instantly. Give them a duration and they animate width, height and opacity together.
Every effect accepts a duration in milliseconds or the words 'fast' (200 ms) and 'slow' (600 ms); the default is 400 ms. The last argument can be a callback function that runs when the effect has finished.
| Method | What it animates |
|---|---|
.show() / .hide() / .toggle() | Instant, or width + height + opacity with a duration |
.fadeIn() / .fadeOut() / .fadeToggle() | Opacity only, then shows or hides the element |
.fadeTo(duration, opacity) | Opacity to a value from 0 to 1; the element stays in the layout |
.slideDown() / .slideUp() / .slideToggle() | Height (and vertical padding), like a drawer opening or closing |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Effects playground</title>
<style>
body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
#box { width: 220px; padding: 16px; background: #0f766e; color: #fff; border-radius: 8px; margin-top: 12px; }
button { margin: 2px; }
</style>
</head>
<body>
<p>
<button type="button" data-fx="toggle">toggle(400)</button>
<button type="button" data-fx="fadeToggle">fadeToggle()</button>
<button type="button" data-fx="slideToggle">slideToggle('slow')</button>
<button type="button" data-fx="fadeTo">fadeTo(300, 0.4)</button>
<button type="button" data-fx="reset">Reset</button>
</p>
<div id="box">Kolam workshop – Saturday 10 am</div>
<p id="status" role="status">Pick an effect.</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const $box = $('#box');
const $status = $('#status');
const done = (name) => () => $status.text(`${name} finished. Visible: ${$box.is(':visible')}`);
$('button[data-fx]').on('click', (event) => {
const fx = $(event.currentTarget).attr('data-fx');
$box.stop(true, true); // finish any running effect first
if (fx === 'toggle') $box.toggle(400, done('toggle'));
if (fx === 'fadeToggle') $box.fadeToggle(done('fadeToggle'));
if (fx === 'slideToggle') $box.slideToggle('slow', done('slideToggle'));
if (fx === 'fadeTo') $box.fadeTo(300, 0.4, done('fadeTo'));
if (fx === 'reset') $box.css('opacity', '').show(done('reset'));
});
</script>
</body>
</html>The playground calls .stop(true, true) before each effect. Without it, clicking quickly would line up effect after effect, and the box would keep blinking long after you stopped clicking. You will learn more about this queue below.
Hidden really means hidden
When .hide(), .fadeOut() or .slideUp() finishes, the element gets display: none. It no longer takes up space, cannot be clicked or focused with the keyboard, and screen readers skip it. That is usually what you want for a closed panel. .fadeTo(300, 0) is different: the element becomes invisible but stays in the layout and can still receive clicks and focus, which can confuse people.
To check the current state in code, use $el.is(':visible'). It returns false for elements that take up no space, including those inside a hidden parent.
Callbacks: doing something after an effect
Effects run in the background, so code on the next line runs immediately, not after the animation. If something must happen when the effect ends – removing the element, moving focus, showing the next step – put it in the callback. When the jQuery object holds several elements, the callback runs once for each element, with this set to that element.
$('#notice').fadeOut(600, () => {
// runs after the fade has finished
$('#notice').remove();
});
// runs straight away, while the fade is still going
$('#status').text('Closing notice…');
// Wait for ALL matched elements to finish: .promise()
$('.card').fadeOut().promise().then(() => {
$('#status').text('All cards hidden.');
});The jQuery effects queue: chaining, delay and stop
Each element has an effects queue. When you chain effects on the same element, they do not run together; each waits for the one before it to finish. .delay(ms) adds a pause to the queue. This makes short sequences easy to write, such as a “Saved!” message that fades in, waits and fades out.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>A toast message with fadeIn, delay and fadeOut</title>
<style>
body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
#toast { display: none; position: fixed; left: 16px; bottom: 16px; padding: 10px 16px; background: #1f2937; color: #fff; border-radius: 6px; }
</style>
</head>
<body>
<p>Your address: 12, Mission Street, Puducherry</p>
<button id="save" type="button">Save address</button>
<div id="toast" role="status">Address saved ✔</div>
<p id="count">Saved 0 times.</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
let saves = 0;
$('#save').on('click', () => {
saves++;
$('#count').text(`Saved ${saves} time(s).`);
$('#toast')
.stop(true, true) // clear the queue and jump to the end
.fadeIn(200)
.delay(1500)
.fadeOut(400);
});
</script>
</body>
</html>.stop()halts the current animation and lets the next queued one start..stop(true)also clears the rest of the queue..stop(true, true)clears the queue and jumps the current animation to its end state..finish()stops everything and jumps all queued animations to their end states.
Watch out: .delay() only delays the effects queue. It does not delay .text(), .addClass() or other non-effect methods in the chain – those run immediately. For a general pause, use setTimeout().
Effects, CSS and reduced motion
jQuery effects change inline styles from JavaScript many times per second. For simple fades and slides, a CSS transition triggered by toggling a class (see CSS Transitions and Animations) is often smoother and keeps design decisions in the stylesheet. jQuery effects are still handy in existing code, and for animating to height: auto, which CSS alone handles poorly.
Some people feel dizzy or sick when things move on screen, and they turn on a “reduce motion” setting in their operating system. Respect it. Setting jQuery.fx.off = true makes every jQuery effect jump straight to its end state, so the page still works – just without movement.
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
jQuery.fx.off = reduceMotion.matches;
// Follow the setting if the user changes it while the page is open
reduceMotion.addEventListener('change', (event) => {
jQuery.fx.off = event.matches;
});