jQuery / Method / .fadeIn() - Gradually Reveal Selected Elements

jQuery's .fadeIn() reveals hidden elements while gradually increasing opacity. In .fadeIn(800), 800 is the effect's duration in milliseconds, rather than a delay before it begins. Put work that depends on completion in its callback, not immediately after the call.

Duration, easing and completion

The .fadeIn() documentation includes the form .fadeIn(duration, easing, complete), whose optional arguments can be omitted. A larger numeric duration makes the effect slower. complete is the function invoked when an element's effect finishes.

Duration Time Expression
Omitted Default 400 ms .fadeIn()
Number Specified milliseconds .fadeIn(800)
"fast" 200 ms .fadeIn("fast")
"slow" 600 ms .fadeIn("slow")
0 Final state without gradual transition .fadeIn(0)

easing controls progress through the effect. The default is swing; linear gives constant progress. Specify it after duration, as in .fadeIn(800, "linear"), rather than putting linear alone in the duration position. The complete example uses the default easing.

Complete example revealing two notices

Save all the code as UTF-8 in fadein-demo.html and open it in a browser. No installation is needed, but an internet connection loads the official full jQuery distribution from its Content Delivery Network (CDN). Use the full build: slim excludes effects and has no .fadeIn().

The code uses 4.0.0. Intermediate opacity, 800/200 ms operation, per-element completion, interrupted reset and instant display were executed with 3.7.1 and 4.0.0. The example omits gradual motion when the operating system requests reduced motion.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Fade in two notice panels</title>
  <style>
    body { font: 16px/1.6 sans-serif; margin: 24px; }
    .panel { display: none; padding: 16px; margin: 12px 0; background: #e4f3f1; }
    button, select { padding: 8px; margin: 4px; }
  </style>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
</head>
<body>
  <h1>Fade in two notice panels</h1>
  <label for="duration">Duration:</label>
  <select id="duration">
    <option value="800">800 ms</option>
    <option value="200">200 ms</option>
  </select>
  <label><input type="checkbox" id="instant"> Show instantly</label>
  <button type="button" id="show">Show notices</button>
  <button type="button" id="reset">Reset</button>
  <div id="notices">
    <div class="panel" id="one">Notice one</div>
    <div class="panel" id="two">Notice two</div>
  </div>
  <p id="result" aria-live="polite"></p>
  <script>
    $(function () {
      const $panels = $("#notices > .panel");
      let completed = 0;
      function report(state) {
        $("#result").text(`state=${state} | completed=${completed}`);
      }
      function clearPanels() {
        $panels.stop(true, false).hide().css("opacity", "");
        completed = 0;
      }
      $("#show").on("click", function () {
        clearPanels();
        const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
        const duration = $("#instant").prop("checked") || reduce
          ? 0 : Number($("#duration").val());
        $("#show").prop("disabled", true);
        report("showing");
        $panels.fadeIn(duration, function () {
          completed++;
          if (completed === $panels.length) {
            report("visible");
            $("#show").prop("disabled", false);
          } else {
            report("showing");
          }
        });
      });
      $("#reset").on("click", function () {
        clearPanels();
        $("#show").prop("disabled", false);
        report("hidden");
      });
      report("hidden");
    });
  </script>
</body>
</html>

Both panels initially have display: none and the result shows:

state=hidden | completed=0
  1. Leave Show instantly off, choose 800 ms and press Show notices. Both panels appear together and the show button is disabled during animation.
  2. When complete, both are visible and state=visible | completed=2 appears. Two counts completed elements, not button clicks.
  3. Press Reset, choose 200 ms and run again to reach the same result faster. Changing the select alone does not alter an effect already running.
  4. During an 800 ms run, press Reset. Both panels hide immediately and state=hidden | completed=0 returns. The old completion does not reappear after its original duration.
  5. Check Show instantly to use duration zero and reveal both without a gradual transition. Detecting the operating system's reduced-motion setting has the same effect.

If no fade is visible, first inspect the instant checkbox and prefers-reduced-motion preference. This example prioritizes reduced motion, so even selecting 800 can yield immediate display.

Completion runs once per element

.fadeIn() does not block subsequent JavaScript until the effect finishes. Reporting completion on the next line can claim it has finished while it is still running. The example increments completed inside the callback to count actual completions.

Each of the two panels invokes its callback once. This is not a single callback for the whole collection. Only when completed reaches $panels.length does the example report visible and re-enable the button. That collection stays fixed during this exercise. In an ordinary callback function, this is the DOM element that just finished.

Interrupted reset and troubleshooting

In .stop(true, false), true clears pending effects and false stops the current effect without completing it. Its completion callback is not invoked, so old completion cannot interfere after Reset. .hide() then hides the panels, clears any inline opacity left halfway through and resets the counter.

Starting again performs the same cleanup and restarts hidden. Disabling Show notices during animation prevents repeated clicks from accumulating queued effects. Cleanup is local to these panels and counters; no global effect setting is changed.

If nothing works, inspect the full jQuery request in Network and errors such as .fadeIn is not a function in Console. An empty selection has no per-element callback. Also check visibility: hidden, hidden ancestors and stronger display rules: changing opacity does not remove every possible hiding condition.