Hello, fellow web dev
If you’ve ever built a <select>
element in HTML, you know the pain: only plain, lifeless text shows up.
It’s a UI crime, honestly.
Not only does it look awful, but the user experience suffers as well.
All you see is plain text and with icons or extra styling, users could scan options faster — but that’s not possible.
And exactly this functionality is what developers have been asking for for decades.
Boom, it’s finally here.
We can customize our <select>
!
So let's have a look
- How it works
- How to style it
- Real world examples
- Browser support
I go deeper into new HTML features like this in my weekly newsletter. If you liked this post, you shouldn't miss this weeks edition.
How It Was Before
If you wanted a rich dropdown — icons, HTML, maybe even interactive content — you needed to fake the dropdown using a combination of:
<div>
or <ul>
for the options,
custom styling,
a little JavaScript to handle opening, closing, and selection.
If you would try to nest HTML code inside the <option>
tag, any browser that seems to render it is either ignoring your inner HTML or treating it as text. You’re stuck with plain text there — no structure, no icons, no nothing.
The New Way
Normally a <select>
would look like this:
<label for="language">Choose a programming language:</label><br>
<select id="language" name="language">
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="ruby">Ruby</option>
</select>
We have our basic tag with nested options.
It’s just a standard <select>
with some <option>
s—nothing fancy. And when it’s closed, all you see is the plain text label.
So… let’s style this up and not make it look like we are stuck in 1996!
In the first step we insert the new <selectedcontent>
just before the first <option>
tag, wrapped in a <button>
. Just like this:
<label for="language">Choose a programming language:</label><br>
<select id="language" name="language">
<button>
<selectedcontent></selectedcontent>
</button>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="ruby">Ruby</option>
</select>
Everytime the selected option changes, HTML creates in the background a clone of the entire HTML inside the <option>
tag via cloneNode()
.
Then it gets displayed in the closed <select>
element.
Hold up — this won’t work yet. First, we need to unlock the new styling engine...
Top comments (8)
Adding a button and a selectedcontent element seems much to just target the styling of the select trigger.
From MDN I understand the main goal is to limit interactive content in the selected option, to make the select trigger work as expected. If you need an element that is selectable and interactive aren't there better UI patterns? Like a dialog?
I think there should be more fine grained options than
:open
and:checked
, but this feels like they are moving too much of the internals outside.Hey David, solid points—and I agree with the core of your concern: the line between styling and re-implementing behavior should be carefully guarded.
That said,
<selectedcontent>
isn’t trying to make selects interactive inside the options—it’s solving the problem of how the closed state of a<select>
looks. For years, we’ve been stuck with “selected label as plain text”—no icons, no branding, no context. This finally breaks that visual barrier without needing to throw out the native behavior.The button +
<selectedcontent>
approach might look heavy, but it's a deliberate trade-off: we retain accessibility, keyboard support, and native dropdown behavior—but with a customizable visual layer on top.Dialogs are great when you're choosing between multiple complex options. But when you're selecting a language, theme, or emoji—and you just want to show a flag or icon next to it—why should we be forced into rebuilding a fake dropdown with JS?
IMO, this isn't breaking the abstraction—it's just giving devs a much-needed window into a black box we've been hacking around for two decades.
Curious to hear how you'd solve this differently while keeping native behavior intact?
That was not what I trying to say. I was going of this paragraph on MDN:
As I understand that it is, going to be, possible to add interactive content and
selectedcontent
is the way to remove the pointer events or content that makes the select trigger change design.So I think
selectedcontent
is a good thing, but it solves a problem that should not exist.In the MDN examples the focus is on styling, so people are guided on the path that leads away from the main goal.
If they are going to use
selectedcontent
just for styling this is a slippery slope, as I see it.I don't know enough of the inner workings of the
select
element to come up with a solution.But they added the ::picker-icon and the ::checkmark.
It seems less intrusive to add more pseudo classes. But I guess that is not possible, I don't think the decision to add
selectedcontent
is taken lightly.Hey David, thanks for expanding—this is a super valuable take, and I really appreciate how you’re framing it.
You're right: the root issue is that the select element was never built for rich interaction, and now we’re patching over a legacy limitation. That quote from MDN nails the intent: make the trigger visually rich without breaking interaction semantics—which is historically a very hard balance in native UI components.
I totally get your concern about selectedcontent feeling like a workaround for a problem that maybe shouldn’t exist in the first place. But here’s the reality: devs have already been hacking selects with fake dropdowns, reinventing accessibility, keyboard nav, ARIA roles, and state management—just to show an icon next to a label.
So if we’re already halfway down the slippery slope, isn’t giving us a safe, native foothold better than pretending it’s not happening?
You're right that pseudo-elements like ::picker-icon and ::checkmark are cleaner and less intrusive. But those only target the decorative flourishes—they don't let you change the actual representation of the selected option, which is where real-world UX demands live.
I do agree with you on one key danger: if devs start stuffing interactive elements inside selectedcontent, misusing it like a slot for buttons and links, we’re going to see chaos. That’s where platform guidance matters more than ever.
But with the current implementation, we finally get a compromise: keep the native behavior, expose the visual layer. That’s progress, even if it’s not perfect.
I agree that there should be a solution. Why not create a new
select
and call it dropdown? HTML and CSS come a long way sinceselect
was added.The way the
multiple
attribute works inselect
breaks the dropdown visual. This is something else they could fix with a new element.Why only fix some parts?
Totally fair point—honestly, creating a new
<dropdown>
element with modern defaults might’ve been cleaner. But the platform tends to evolve existing elements instead of replacing them, probably for backwards compatibility.Still, I agree—it feels half-solved. Would love to see a full rethink too.
i love the new set up, It better now
Good!
Some comments may only be visible to logged-in visitors. Sign in to view all comments.