.parentsUntil([stop] [, filter]) (since jQuery 1.4) returns ancestors of each matched element up to but not including a stop selector, DOM node, or jQuery object (node/jQuery stop since 1.6). Optional filter keeps only matching ancestors in that range. Returns a new jQuery set; does not change the DOM.
Remember
$("li.item-a").parentsUntil(".level-1");
$("li.item-2").parentsUntil("ul.level-1", ".yes");
$("button").parentsUntil($("#panel")); // stop at jQuery (1.6+)
// parentsUntil(stop) → ancestors before stop
// parents() → all ancestors
// parent() → one level up
// closest() → nearest match (incl. self)
Pick a start, choose where to stop climbing, then optionally filter the range.
Select the starting element(s) — e.g. $("li.item-a").
Call .parentsUntil(stop) with a selector, Element, or jQuery object.
Optionally pass a second filter selector to keep matching ancestors only.
Chain methods on the new set (.append(), .addClass(), …).
Remember: the stop match itself is never included.
Piece
Required?
Role
Matched set
Yes
Starting element(s)
stop
No
Selector / Element / jQuery — climb until here (excluded)
filter
No
Keep only matching ancestors in the range
Return value
—
New jQuery set (unique ancestors before stop)
Pseudocode
Pseudocode
call $(starts).parentsUntil(stop?, filter?)
result = empty set
for each start in the matched set:
node = start.parentElement
while node is an element:
if stop is set AND node matches stop:
break // do not include stop
if no filter OR node matches filter:
add node to result
node = node.parentElement
return unique ancestors as a new jQuery object
Click a link → nav / ul / li get [path]
section and body stay unmarked
How It Works
Delegate. Listen for clicks on links inside the section.
Clear. Remove previous path marks.
Until. Collect ancestors before section.
Mark. Only the in-section path is tagged.
Edge Cases & Pitfalls
Common surprises when stopping the climb early.
stop
Stop match is never included
Need the boundary too? Combine with .addBack() patterns or select the stop separately.
miss
Missing stop → full chain
If the stop is omitted or never found, you get the same set as .parents().
filter
Filter is the second argument
.parentsUntil(stop, filter) — swap them and you change the stop, not the filter.
self
Start element is never included
Climbing begins at the parent. Need self-or-ancestor? Use .closest().
version
Element / jQuery stop needs 1.6+
Selector stop works since 1.4. Passing a DOM node or jQuery object requires jQuery 1.6+.
Compatibility
Browser Support
.parentsUntil() has been part of jQuery since 1.4 (Element/jQuery stop since 1.6). It works in every browser that runs your loaded jQuery version — no separate browser feature flag.
✓ Stable · jQuery 1.4+
jQuery .parentsUntil()
Supported across jQuery 1.x (1.4+), 2.x, and 3.x. Prefer a current jQuery 3.x build. Traversal uses the live DOM tree.
100%With jQuery
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
.parentsUntil()Universal
Bottom line: Cut the ancestor chain at a stop. Prefer .parents() for the full climb, .parent() for one hop.
Analysis
Performance Notes
Approach
Cost
Best for
.parent()
Cheapest upward
Known direct wrapper
.closest(sel)
Stops at first match
One nearest match / self
.parentsUntil(stop)
Walk until stop
Path inside a known container
.parents()
Walks to root
Full ancestor chain
Prefer .parentsUntil() when you know the outer boundary — fewer nodes than climbing to html.
Remember
Key Takeaways
Role: ancestors before a stop — since jQuery 1.4.
Stop: selector, Element, or jQuery (1.6+) — never included.
Filter: optional second arg keeps matching ancestors in range.
Fallback: no stop → same as .parents().
One line:.parentsUntil() collects ancestors until a boundary — and leaves that boundary out.
Frequently Asked Questions
.parentsUntil() collects ancestors of each matched element up to — but not including — a stop selector, DOM node, or jQuery object. An optional second filter keeps only ancestors that match.
.parents() walks all the way toward the document root (optionally filtered). .parentsUntil(stop) stops before the stop match, so outer wrappers past that point are excluded.
No. The stop match is the boundary and is never included. Ancestors between the start and that boundary are returned.
If the stop is omitted or not found, .parentsUntil() behaves like .parents() with no selector — every ancestor is selected.
Yes, since jQuery 1.6. The first argument can be a selector string, a DOM Element, or a jQuery object. The optional second argument is always a filter selector.
No. Like other jQuery traversing methods, it only queries the existing DOM and returns a new collection.