Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools

Recently Stefan Judis shared how to to style the browse button of a file selector using the ::file-selector-button pseudo-element TIL – you can style the file input “browse” button using `::file-selector-button`.?Supported in Firefox, Chromiums starting with 89 & Safari Tech preview.? MDN: https://t.co/56jACY9qK1? Compat data pr: https://t.co/vrFNS4LdISVideo alt: Example of a styled browse button. pic.twitter.com/3YQ0njkX0J— …

Recently Stefan Judis shared how to to style the browse button of a file selector using the ::file-selector-button pseudo-element

But what about other complex elements in the browser? How can we tweak individual parts of those? Take <audio> for example: is there a pseudo-element we can use to style the play button?

~

Table of Contents

  1. Dissecting <input type="file" />
  2. How to use DevTools to peek inside <input type="file" />
  3. Dissecting <audio>
  4. Is there a catch?
  5. One last thing

~

# Dissecting <input type="file" />

Before we answer the question above, let’s first take a look at the <input type="file" /> Stefan used. Below is screenshot of how it’s rendered in Chromium on Mac, with a few extra outlines added.

Even though we only type 1 element in our HTML code, we see it consists of two parts:

  1. A “Choose File” button
  2. A label reading “No file chosen”

Internally, this is also how the browser builds it. We type in:

<input type="file" />

But what’s being rendered is this:

<input type="button" value="Choose file" pseudo="-webkit-file-upload-button" id="file-upload-button">
<span aria-hidden="true">No file chosen</span>

(I’ll show you further down this post how I know this ?)

The ::file-selector-button selector Stefan mentioned targets only the <input type="button" …> you see there. Using it you can style the button, like he did.

? If you’re paying close attention you might notice that the pseudo-element used is ::file-selector-button, whilst the pseudo attribute of the button reads -webkit-file-upload-button. More on that further down the post ?

~

# How to use DevTools to peek inside <input type="file" />

In the Chromium DevTools we don’t get to see the two elements that make up <input type="file" />. That’s because this information as is hidden in the Shadow DOM.

Thankfully there is a way to have DevTools show them. To do so, open DevTools’ Settings, and under Elements check the option that reads “Show user agent Shadow DOM”.

? Firefox or ? Safari user? The DevTools in Firefox/Safari have this option enabled out of the box.

Once enabled you’ll see #shadow-root (user-agent) appear in the Elements Tree for all elements that are built that way (and there quite a few!).

<input type="file">
  ↳ #shadow-root (user-agent)
      <input type="button" value="Choose file" pseudo="-webkit-file-upload-button" id="file-upload-button">
      <span aria-hidden="true">No file chosen</span>
</input>

☝️ Having this option enabled all the time can be quite distracting. I personally only turn it on when I need it.

~

# Dissecting <audio>

Winging back to our initial question “is there a pseudo-element we can use to style the play button?”, we can use the DevTools we can see it’s underlying structure.

In Chromium we get back this structure:

<audio controls="" src="/media/cc0-audio/t-rex-roar.mp3">
  ↳ #shadow-root (user-agent)
    <div pseudo="-webkit-media-controls" class="phase-ready state-stopped">
      <div pseudo="-webkit-media-controls-overlay-enclosure">
        <input pseudo="-internal-media-controls-overlay-cast-button" type="button" aria-label="play on remote device" style="display: none;">
      </div>
      <div pseudo="-webkit-media-controls-enclosure">
        <div pseudo="-webkit-media-controls-panel">
          <input type="button" pseudo="-webkit-media-controls-play-button" aria-label="play" class="pause" style="">
          <div aria-label="elapsed time: 0:00" pseudo="-webkit-media-controls-current-time-display" style="">0:00</div>
          <div aria-label="total time: / 0:02" pseudo="-webkit-media-controls-time-remaining-display" style="">/ 0:02</div>
          <input type="range" step="any" pseudo="-webkit-media-controls-timeline" max="2.115918" aria-label="audio time scrubber 0:00 / 0:02" aria-valuetext="elapsed time: 0:00">
          <div pseudo="-webkit-media-controls-volume-control-container" class="closed" style="">
            <div pseudo="-webkit-media-controls-volume-control-hover-background"></div>
            <input type="range" step="any" max="1" aria-valuemax="100" aria-valuemin="0" aria-label="volume" pseudo="-webkit-media-controls-volume-slider" aria-valuenow="100" class="closed" style=""><input type="button" pseudo="-webkit-media-controls-mute-button" aria-label="mute" style="">
          </div>
          <input type="button" pseudo="-webkit-media-controls-fullscreen-button" aria-label="enter full screen" style="display: none;">
          <input type="button" aria-label="show more media controls" title="more options" pseudo="-internal-media-controls-overflow-button" style="">
        </div>
      </div>
      <div role="menu" aria-label="Options" pseudo="-internal-media-controls-text-track-list" style="display: none;"></div>
      <div pseudo="-internal-media-controls-overflow-menu-list" role="menu" class="closed" style="display: none;">
        <label pseudo="-internal-media-controls-overflow-menu-list-item" role="menuitem" tabindex="0" aria-label=" Play " style="display: none;">
          <input type="button" pseudo="-webkit-media-controls-play-button" tabindex="-1" aria-label="play" class="pause" style="display: none;">
          <div aria-hidden="true">
            <span>Play</span>
          </div>
        </label>
        <label pseudo="-internal-media-controls-overflow-menu-list-item" role="menuitem" tabindex="0" aria-label="enter full screen Full screen " style="display: none;">
          <input type="button" pseudo="-webkit-media-controls-fullscreen-button" aria-label="enter full screen" tabindex="-1" style="display: none;">
          <div aria-hidden="true">
            <span>Full screen</span>
          </div>
        </label>
        <label pseudo="-internal-media-controls-overflow-menu-list-item" role="menuitem" tabindex="0" aria-label="download media Download " class="animated-0" style="">
          <input type="button" aria-label="download media" pseudo="-internal-media-controls-download-button" tabindex="-1" style="">
          <div aria-hidden="true">
            <span>Download</span>
          </div>
        </label>
        <label pseudo="-internal-media-controls-overflow-menu-list-item" role="menuitem" tabindex="0" aria-label=" Mute " class="animated-2" style="display: none;">
          <input type="button" pseudo="-webkit-media-controls-mute-button" tabindex="-1" aria-label="mute" style="display: none;">
          <div aria-hidden="true">
            <span>Mute</span>
          </div>
        </label>
        <label pseudo="-internal-media-controls-overflow-menu-list-item" role="menuitem" tabindex="0" aria-label="play on remote device Cast " class="animated-1" style="display: none;">
          <input pseudo="-internal-media-controls-cast-button" type="button" aria-label="play on remote device" tabindex="-1" style="display: none;">
          <div aria-hidden="true">
            <span>Cast</span>
          </div>
        </label>
        <label pseudo="-internal-media-controls-overflow-menu-list-item" role="menuitem" tabindex="0" aria-label="show closed captions menu Captions " class="animated-0" style="display: none;">
          <input aria-label="show closed captions menu" type="button" pseudo="-webkit-media-controls-toggle-closed-captions-button" tabindex="-1" style="display: none;">
          <div aria-hidden="true">
            <span>Captions</span>
          </div>
        </label>
      </div>
    </div>
</audio>

Or visually, with outlines added:

With a bit of digging we can find the the play button on line #9, and extract its pseudo attribute.

<input type="button" pseudo="-webkit-media-controls-play-button" aria-label="play" class="pause" style="">

? To style the play button we can use ::-webkit-media-controls-play-button

~

# Is there a catch?

While the ::-webkit-media-controls-play-button selector above works, there’s a catch though: it only works in Chromium based browsers, and this for several reasons:

  1. Every browser engine has its own implementation for what makes up an <audio> element. Shown below is a comparison of the UI for the <audio> as seen in Firefox, Chromium, and Safari.

    Whilst all implementation contain a play button, not all — for example — contain an element that indicates the current time. Styling that wouldn’t be possible.

  2. Not all browser expose the same parts of the UI using pseudo-elements. When it comes to <audio> for example, only Chromium exposes parts of its UI. Firefox and Safari don’t expose any pseudo-element for <audio>

    And even if they would, the wouldn’t use ::-webkit-media-controls-play-button for it.

Another aspect to take into account is that ::-webkit-media-controls-play-button is something that Chromium decided to use. This wasn’t discussed with any other browser vendor. As Thomas Steiner warns:

~

# One last thing

To close off I still owe you an explanation to why Chromium lists ::-webkit-file-upload-button for the browse button of <input type="file" />, instead of ::file-selector-button.

This is because they first exposed it using their own internal ::-webkit-file-upload-button name. It was only later that the CSS Working Group decided to standardize it to ::file-selector-button.

~

Did this help you out? Like what you see?
Thank me with a coffee.

I don’t do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.


Print Share Comment Cite Upload Translate
APA
Bramus! | Sciencx (2024-03-28T19:59:37+00:00) » Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools. Retrieved from https://www.scien.cx/2021/04/15/identify-and-extract-pseudo-element-selectors-from-built-in-html-elements-using-devtools/.
MLA
" » Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools." Bramus! | Sciencx - Thursday April 15, 2021, https://www.scien.cx/2021/04/15/identify-and-extract-pseudo-element-selectors-from-built-in-html-elements-using-devtools/
HARVARD
Bramus! | Sciencx Thursday April 15, 2021 » Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools., viewed 2024-03-28T19:59:37+00:00,<https://www.scien.cx/2021/04/15/identify-and-extract-pseudo-element-selectors-from-built-in-html-elements-using-devtools/>
VANCOUVER
Bramus! | Sciencx - » Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools. [Internet]. [Accessed 2024-03-28T19:59:37+00:00]. Available from: https://www.scien.cx/2021/04/15/identify-and-extract-pseudo-element-selectors-from-built-in-html-elements-using-devtools/
CHICAGO
" » Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools." Bramus! | Sciencx - Accessed 2024-03-28T19:59:37+00:00. https://www.scien.cx/2021/04/15/identify-and-extract-pseudo-element-selectors-from-built-in-html-elements-using-devtools/
IEEE
" » Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools." Bramus! | Sciencx [Online]. Available: https://www.scien.cx/2021/04/15/identify-and-extract-pseudo-element-selectors-from-built-in-html-elements-using-devtools/. [Accessed: 2024-03-28T19:59:37+00:00]
rf:citation
» Identify and Extract Pseudo-Element Selectors from built-in HTML Elements using DevTools | Bramus! | Sciencx | https://www.scien.cx/2021/04/15/identify-and-extract-pseudo-element-selectors-from-built-in-html-elements-using-devtools/ | 2024-03-28T19:59:37+00:00
https://github.com/addpipe/simple-recorderjs-demo