363

I am wondering if there is a way to have "OR" logic in jQuery selectors. For example, I know an element is either a descendant of an element with class classA or classB, and I want to do something like elem.parents('.classA or .classB'). Does jQuery provide such functionality?

6 Answers 6

567

Use a comma.

'.classA, .classB'

You may choose to omit the space.

9
  • 48
    It should be noted this isn't really an 'or' selector, more like multiple selectors in one.
    – alex
    Commented Feb 15, 2010 at 3:57
  • 57
    @alex: but it won't select the same element twice (which a concatenation operator would). It really is an OR selector because it creates a UNION of two or more sets (whereas AND is an intersection).
    – cletus
    Commented Feb 15, 2010 at 3:59
  • Thanks, that works. Because of a debugging oversight I thought that using a comma means 'AND'.
    – Suan
    Commented Feb 15, 2010 at 4:00
  • 43
    AND would be .classA.classB. Commented Feb 15, 2010 at 4:28
  • 2
    It actually depends on what the original question implied... ie: classically an 'or' operator will short-circuit. Thus an 'or' operator in jquery parlance, could possibly short-circuit too.
    – Mathew
    Commented Apr 22, 2012 at 1:58
84

Using a comma may not be sufficient if you have multiple jQuery objects that need to be joined.

The .add() method adds the selected elements to the result set:

// classA OR classB
jQuery('.classA').add('.classB');

It's more verbose than '.classA, .classB', but lets you build more complex selectors like the following:

// (classA which has <p> descendant) OR (<div> ancestors of classB)
jQuery('.classA').has('p').add(jQuery('.classB').parents('div'));
24

I have written an incredibly simple (5 lines of code) plugin for exactly this functionality:

https://github.com/byrichardpowell/jquery-or/

It allows you to effectively say "get this element, or if that element doesnt exist, use this element". For example:

$( '#doesntExist' ).or( '#exists' );

Whilst the accepted answer provides similar functionality to this, if both selectors (before & after the comma) exist, both selectors will be returned.

I hope it proves helpful to anyone who might land on this page via google.

6
  • 4
    That's not how the boolean OR operator works. If both selectors return elements, the OR operator should return all of them and not only the elements of the first selector. Your plugin should be named "ifEmpty" or "else" or something like that.
    – Alp
    Commented Mar 12, 2013 at 16:16
  • 17
    @Alp: Consider the behavior of "a" || "b" vs. null || "b" in vanilla JS. If we apply the same behavior here, $(a).or(b) should return $(a) if it exists, otherwise it should return $(b). I don't think there's anything wrong with this nomenclature, as the "or" matches the behavior of the JS "||" (or) operator.
    – FtDRbwLXw6
    Commented Oct 18, 2013 at 14:35
  • 6
    I also see it as an or. What other are talking about is more like a concat or merge action. Commented Nov 9, 2015 at 17:55
  • 1
    Personally I would not call this "or", as it may lead to confusion (even if it may technically be correct as it is a special kind of if/or). This is effectively null coalescence, which is called different things and have different operators in different languages: en.wikipedia.org/wiki/Null_coalescing_operator Commented Dec 4, 2017 at 10:15
  • 1
    @lilHar I couldn't disagree more. "xor" is specifically a Boolean operator, and always returns a truth value, true only if its two arguments have different truth values. It is NOT equivalent to the short circuiting "or" that returns the first true thing... not even close.
    – Dan H
    Commented Aug 24, 2021 at 18:56
18

If you're looking to use the standard construct of element = element1 || element2 where JavaScript will return the first one that is truthy, you could do exactly that:

element = $('#someParentElement .somethingToBeFound') || $('#someParentElement .somethingElseToBeFound');

which would return the first element that is actually found. But a better way would probably be to use the jQuery selector comma construct (which returns an array of found elements) in this fashion:

element = $('#someParentElement').find('.somethingToBeFound, .somethingElseToBeFound')[0];

which will return the first found element.

I use that from time to time to find either an active element in a list or some default element if there is no active element. For example:

element = $('ul#someList').find('li.active, li:first')[0] 

which will return any li with a class of active or, should there be none, will just return the last li.

Either will work. There are potential performance penalties, though, as the || will stop processing as soon as it finds something truthy whereas the array approach will try to find all elements even if it has found one already. Then again, using the || construct could potentially have performance issues if it has to go through several selectors before finding the one it will return, because it has to call the main jQuery object for each one (I really don't know if this is a performance hit or not, it just seems logical that it could be). In general, though, I use the array approach when the selector is a rather long string.

2
  • 1
    I think find('.somethingToBeFound, .somethingElseToBeFound') is not same as || construct. Because find if .somethingElseToBeFound is in DOM before .somethingToBeFound, it would be returned even if .somethingToBeFound exists.
    – remo
    Commented Apr 29, 2020 at 11:57
  • Maybe Jquery has changed in the last 10 years but this doesn't seem to work for me. Even if it doesn't find anything, it still returns an object.
    – Clonkex
    Commented Aug 17, 2023 at 0:08
1

Finally I've found hack how to do it:

div:not(:not(.classA,.classB)) > span

(selects div with class classA OR classB with direct child span)

-2

Daniel A. White Solution works great for classes.

I've got a situation where I had to find input fields like donee_1_card where 1 is an index.

My solution has been

$("input[name^='donee']" && "input[name*='card']")

Though I am not sure how optimal it is.

Not the answer you're looking for? Browse other questions tagged or ask your own question.