Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at the jQuery Conference 2010 (Boston, MA) with: Andrew Wirick
Ben Nadel at the jQuery Conference 2010 (Boston, MA) with: Andrew Wirick@amWirick )

Checking To See If An Element Has A CSS Pseudo-Class In JavaScript

By Ben Nadel on

This morning, I sat down to see if I could detect "autofill" behaviors in the browser. In doing so, I came across several StackOverflow posts that mentioned a ":-webkit-autofill" pseudo-class getting applied to inputs in WebKit-based browsers. When I read this, it occurred to me that I didn't know how to use JavaScript in order to check to see if an input Element actually had a given pseudo-class applied to it. After some Googling, I came across a great post by Pallxk on working with pseudo-classes in JavaScript. That article turned me onto the Element.matches() method, which is what I wanted to play around with today.


 
 
 

 
 
 
 
 

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

According to the Mozilla Developer Network (MDN), the Element.matches() method tests to see if the contextual node matches the given CSS selector. The .matches() method has solid support going back to IE9; though, IE uses a different method name (.msMatchesSelector() as opposed to .matches()). As such, we can pretty much depend on this method in all modern browsers.

To see the Element.matches() method in action, I've put together a simple demo that tests for a given set of CSS pseudo-classes on a single "username" form element. We can then use the Developer Tools to explicitly apply pseudo-classes like ":hover" and ":active" to the "username" before we use JavaScript to see if those pseudo-classes can be found on the given element.

NOTE: I chose to create a "username" field on purpose so that my browser would have some autofill capabilities that it would apply to the field.

  • <!doctype html>
  • <html lang="en">
  • <head>
  • <meta charset="utf-8" />
  • <title>
  • Checking To See If An Element Has A CSS Pseudo-Class In JavaScript
  • </title>
  •  
  • <link rel="stylesheet" type="text/css" href="./demo.css" />
  • </head>
  • <body>
  •  
  • <h1>
  • Checking To See If An Element Has A CSS Pseudo-Class In JavaScript
  • </h1>
  •  
  • <form method="get" action="./">
  • <label for="username">Username:</label>
  • <input type="text" id="username" name="username" class="username" />
  • <button type="submit">Login</button>
  • </form>
  •  
  • <ul>
  • <li>
  • <a href="javascript:testFor( ':-webkit-autofill' )">
  • Test for <code>:-webkit-autofill</code>
  • </a>
  • </li>
  • <li>
  • <a href="javascript:testFor( ':hover' )">
  • Test for <code>:hover</code>
  • </a>
  • </li>
  • <li>
  • <a href="javascript:testFor( ':active' )">
  • Test for <code>:active</code>
  • </a>
  • </li>
  • <li>
  • <a href="javascript:testFor( ':focus' )">
  • Test for <code>:focus</code>
  • </a>
  • </li>
  • </ul>
  •  
  • <script type="text/javascript">
  •  
  • // Gather our DOM references.
  • var username = document.querySelector( "#username" );
  •  
  • // --------------------------------------------------------------------------- //
  • // --------------------------------------------------------------------------- //
  •  
  • // I test the USERNAME input for the existence of the given pseudo-class.
  • function testFor( pseudoClass ) {
  •  
  • console.group( "Testing for Pseudo-Class" );
  • console.log( "Pseudo-class:", pseudoClass );
  • console.log( "Has pseudo-class:", matches( username, pseudoClass ) );
  • console.log( "Class list:", username.classList.toString() ); // IE doesn't support .value.
  • console.groupEnd();
  •  
  • }
  •  
  •  
  • // I determine if the given node matches the given selector.
  • function matches( node, selector ) {
  •  
  • // Most modern browsers support the ".matches" method. However, IE9+ uses a
  • // non-standard method name. As such, we can fall-back to the IE version when
  • // the standard one doesn't exist and that should cover all the modern
  • // browsers that are in use.
  • // --
  • // READ MORE: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
  • var nativeMatches = ( node.matches || node.msMatchesSelector );
  •  
  • // CAUTION: If an invalid pseudo-selector is used in Firefox or IE, the
  • // browser will throw a SyntaxError, "is not a valid selector". It will do
  • // the same for .querySelector() as well, just an FYI.
  • try {
  •  
  • return( nativeMatches.call( node, selector ) );
  •  
  • } catch ( error ) {
  •  
  • // In the case of an error, we're going to assume it's a pseudo-selector
  • // issue and NOT a general support issue (since we don't care about
  • // really old browsers).
  • return( false );
  •  
  • }
  •  
  • }
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, there's very little going on in this demo. Essentially, I'm looking for the node.matches() method but, will fall-back to the node.msMatchesSelector() method in IE. I then use the chosen method to look for the given CSS pseudo-class.

Now, if I run this in the browser, explicitly add the ":hover" pseudo-class and then autofill the username, we get the following test outcome:


 
 
 

 
 Checking for CSS pseudo-classes on an element using JavaScript and Element.matches(). 
 
 
 

As you can see, we were able to successfully detect the applied CSS pseudo-classes in JavaScript. But, it should be noted that the browser will throw a SyntaxError if you try to use a pseudo-class Selector that the browser doesn't support. For example, all the browsers allow you to test for ":hover", since it's universally supported. But, all browsers other than Chrome will throw a SyntaxError when you test for, ":-webkit-autofill". That's why we need to wrap the underlying call to matches() inside a try/catch block.

Anyway, this is more of a note-to-self; but, it's definitely good to know that there's a cross-browser way to check an element for CSS pseudo-classes. If nothing else, this will help me when trying to detect autofill behaviors in the browser.



Looking For A New Job?

Ooops, there are no jobs. Post one now for only $29 and own this real estate!

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

@All,

I should mention that you can also search for the pseudo-classes using node.querySelector() and node.querySelectorAll(). In fact, on the MDN page, that's how they polyfill the .matches() method -- using the .querySelectorAll() and then iterating over the matches and checking for element reference equality.

Reply to this Comment

Great information. Since last week, I am gathering details about the AngularJS experience.
There are some amazing details on your blog which I didn't know. Thanks.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.