Show, Hide, Fade & Slide
Effects were one of jQuery's most loved features. One line could fade in a message or slide open a menu, at a time when browsers had no CSS transitions. You will meet .fadeIn() and .slideToggle() in almost every older site.
In this lesson you will learn jQuery's built-in effects, how durations, easing and callbacks work, and how to get the same result today with the hidden attribute, CSS transitions, the <details> element and the Web Animations API. The next lesson covers custom animations with .animate().
Instant: hide(), show() and toggle()
Without arguments, these change visibility immediately:
$("#banner").hide(); // sets display: none
$("#banner").show(); // restores the element's normal display value
$("#banner").toggle(); // hide if visible, show if hidden
$("#banner").toggle(isOpen); // show when true, hide when false
// Plain JavaScript: the hidden attribute
const banner = document.querySelector("#banner");
banner.hidden = true;
banner.hidden = false;
banner.hidden = !banner.hidden;hidden is a standard HTML attribute that the browser styles as display: none. One catch: if your CSS sets display: flex on that element, the CSS rule wins and hidden stops working. Add [hidden] { display: none !important; } to your stylesheet to be safe.
Animated: durations, fades and slides
Pass a duration and the change becomes an animation. Durations are in milliseconds, or the words "fast" (200 ms) and "slow" (600 ms). The default is 400 ms.
| Method | Animates |
|---|---|
.show(400), .hide(400), .toggle(400) | width, height and opacity together |
.fadeIn(), .fadeOut(), .fadeToggle() | opacity, then display |
.fadeTo(600, 0.4) | opacity to a given value (stays visible) |
.slideDown(), .slideUp(), .slideToggle() | height, like a blind rolling |
Most effect methods take the same optional arguments in this order: duration, easing, complete. Easing describes the speed curve; jQuery includes only "swing" (the default: slow start and end) and "linear". The complete callback runs once for each element when its animation ends.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery effects</title>
<style>
#notice { background: #fff3c4; border: 1px solid #e0c060; padding: 0.8rem; max-inline-size: 24rem; border-radius: 6px; }
.controls button { margin: 0.2rem; }
</style>
</head>
<body>
<div class="controls">
<button data-fx="hide">hide()</button>
<button data-fx="show">show()</button>
<button data-fx="fadeOut">fadeOut()</button>
<button data-fx="fadeIn">fadeIn()</button>
<button data-fx="slideUp">slideUp()</button>
<button data-fx="slideDown">slideDown()</button>
<button data-fx="slowFade">fadeToggle("slow")</button>
<button data-fx="dim">fadeTo(400, 0.3)</button>
</div>
<div id="notice">
<strong>Exam notice:</strong> Class 12 practical exams in Kochi start on Monday at 9 am.
</div>
<p id="status">Click a button.</p>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
const $notice = $("#notice");
const done = (name) => () => $("#status").text(name + " finished");
$(".controls").on("click", "button", function () {
const fx = $(this).attr("data-fx");
$("#status").text(fx + " running...");
$notice.stop(true, true); // finish any running effect first
if (fx === "hide") { $notice.hide(); done(fx)(); } // no arguments: instant
if (fx === "show") { $notice.show(); done(fx)(); }
if (fx === "fadeOut") $notice.fadeOut(done(fx));
if (fx === "fadeIn") $notice.fadeIn(done(fx));
if (fx === "slideUp") $notice.slideUp(done(fx));
if (fx === "slideDown") $notice.slideDown(done(fx));
if (fx === "slowFade") $notice.fadeToggle("slow", "linear", done(fx));
if (fx === "dim") $notice.fadeTo(400, 0.3, done(fx));
});
</script>
</body>
</html>$notice.stop(true, true) ends any animation still running so fast clicks do not pile up. You will learn more about the animation queue in Animations & CSS Alternatives.
Waiting for effects to finish
Callbacks get messy when several steps must happen in order. .promise() returns a promise-like object that settles when every animation on the set has finished, so you can use .then() or await:
async function closeAlert() {
await $("#alert").fadeOut(300).promise();
$("#alert").remove();
$("#next-step").fadeIn();
}The modern way: classes and CSS transitions
Today most fades and slides are done in CSS. JavaScript only switches a class, and a CSS transition animates the change. This keeps the animation smooth because the browser can run opacity changes off the main thread.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CSS and details</title>
<style>
.toast { opacity: 0; translate: 0 0.5rem; transition: opacity 0.3s, translate 0.3s; background: #1f3b57; color: #fff; padding: 0.7rem 1rem; border-radius: 6px; inline-size: fit-content; }
.toast.visible { opacity: 1; translate: 0 0; }
details { border: 1px solid #ccc; border-radius: 6px; padding: 0.4rem 0.8rem; margin: 0.4rem 0; max-inline-size: 26rem; }
summary { cursor: pointer; font-weight: bold; }
</style>
</head>
<body>
<button id="save">Save profile</button>
<p class="toast" id="toast" role="status">Profile saved for Isha</p>
<h3>Hostel FAQ (no JavaScript at all)</h3>
<details name="faq">
<summary>What time is dinner?</summary>
<p>Dinner is served from 7:30 pm to 9:30 pm.</p>
</details>
<details name="faq">
<summary>Are visitors allowed?</summary>
<p>Yes, on Sundays between 10 am and 5 pm.</p>
</details>
<script>
const toast = document.querySelector("#toast");
document.querySelector("#save").addEventListener("click", () => {
toast.classList.add("visible");
setTimeout(() => toast.classList.remove("visible"), 2000);
});
</script>
</body>
</html>The toast fades and slides with no library. The FAQ uses <details> and <summary>, which open and close with no script at all; giving them the same name makes them an exclusive accordion where opening one closes the other. For a smooth height animation like .slideDown(), see CSS Transitions.
Fading with the Web Animations API
When you need JavaScript control (for example, to wait for the end), every element has an animate() method. It returns an Animation object whose finished property is a real promise:
const box = document.querySelector("#notice");
const fade = box.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 400, easing: "ease-in" });
await fade.finished;
box.hidden = true;| jQuery | Modern equivalent |
|---|---|
.hide() / .show() / .toggle() | el.hidden = true / false / !el.hidden |
.fadeIn() / .fadeOut() | toggle a class with a CSS opacity transition, or el.animate() |
.slideToggle() on an FAQ | <details> and <summary> |
| complete callback | transitionend event or await animation.finished |
Common mistakes
- Starting a new effect on every click without stopping the old one. Effects queue up and keep playing after the user stops clicking. Call
.stop()first, or use CSS classes. - Using the slim build. It has no animated effects;
.fadeInis not a function. - Putting code that needs the hidden state right after
.fadeOut(). The fade has only just started. Use the complete callback or.promise(). - CSS
displayrules overridinghidden. Add a[hidden] { display: none !important; }rule.
Key points
.hide(),.show()and.toggle()are instant without a duration and animated with one.- Fades change opacity; slides change height; durations are milliseconds,
"fast"(200) or"slow"(600), default 400. - Arguments follow the order duration, easing, complete;
.promise()lets youawaitthe end. - Modern code uses the
hiddenattribute, CSS transitions on a class,<details>, andelement.animate(). - Respect
prefers-reduced-motion;$.fx.off = trueturns jQuery effects off.
Exercise
Make a "Today's special" box that is hidden when the page loads. Add one button that uses jQuery .fadeToggle(300) to show and hide it, and changes its own text to "Hide special" or "Show special" in the complete callback depending on whether the box is now visible (use .is(":visible")). Then add a second box and button that do the same with the hidden attribute and plain JavaScript (no animation needed).
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Today's special</title>
<style>.special { background: #e6f4ea; padding: 0.6rem; max-inline-size: 20rem; }</style>
</head>
<body>
<button id="jq-btn">Show special</button>
<div class="special" id="jq-box" style="display: none">Paneer tikka thali, ₹220</div>
<button id="js-btn">Show special</button>
<div class="special" id="js-box" hidden>Veg biryani, ₹180</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
$("#jq-btn").on("click", function () {
const $btn = $(this);
$("#jq-box").stop(true, true).fadeToggle(300, function () {
$btn.text($(this).is(":visible") ? "Hide special" : "Show special");
});
});
const jsBox = document.querySelector("#js-box");
document.querySelector("#js-btn").addEventListener("click", (event) => {
jsBox.hidden = !jsBox.hidden;
event.currentTarget.textContent = jsBox.hidden ? "Show special" : "Hide special";
});
</script>
</body>
</html>The jQuery button reads the visibility only in the complete callback, after the fade has finished; the plain version can read hidden straight away because the change is instant.
Quick Quiz
1. How long does .fadeIn() take when you pass no duration?
The default duration of jQuery effects is 400 milliseconds.
2. Which easing names are built into jQuery without plugins?
Other easings need a plugin such as jQuery UI; CSS has many built in.
3. What is the simplest modern replacement for an FAQ built with .slideToggle()?
<details> opens and closes natively, and a shared name makes an exclusive accordion.
4. Why does code placed directly after .fadeOut() see the element still visible?
Effects are asynchronous; use the complete callback or .promise() to run code afterwards.
Learn jQuery with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
