Internet browsers ship new options on a regular basis, however what enjoyable is it if we are able to’t construct foolish and enjoyable issues with them?
On this article, let’s go over just a few demos that I’ve made by utilizing the brand new customizable function, and stroll by means of the primary steps and strategies that I’ve used to implement them.
I hope they get you as excited as I’m about customized selects, and provide you with nearly sufficient data to get began creating your individual. Yours is perhaps extra, you recognize, helpful than mine, and possibly for good causes, however I like going a bit of bit overboard on foolish concepts as a result of that offers me a greater likelihood to study.
Earlier than we begin, a phrase about browser assist: the demos on this article solely run on current Chromium-based browsers as a result of that’s the place customizable selects are carried out proper now. Nevertheless, this function is designed in a manner that doesn’t break non-supporting browsers. In spite of everything, a custom-made aspect remains to be a aspect. So, if the browser you’re utilizing doesn’t assist customizable selects, you’ll simply see regular selects and choices in these demos, and that’s nice. It’ll simply be lots much less enjoyable.
Curved stack of folders
Let’s get began with the primary demo: a stack of folders to select from, with a twist:
We’ll begin with some HTML code first. We don’t want loads of difficult markup right here as a result of every possibility is simply the title of the folder. We will draw the folder icons later with CSS solely.
You’ll discover that we’ve used parts contained in the parts, to wrap every folder title. That’s going to be helpful for styling the chosen folder title later. Although that is only a , having the ability to do that is fairly a giant change from what was beforehand attainable.
That’s as a result of, up till very not too long ago, s may solely include textual content, as a result of that’s the one factor that might seem inside choices of a choose. The HTML parser has now been relaxed to permit for lots extra HTML parts to be embedded in choices. Browsers that don’t assist customizable selects will simply ignore these further parts and show the textual content solely.
So, right here’s what our stack of folders seems like to this point:

Subsequent up, and that is an important factor you’ll wish to do to decide into the customizable choose function: let’s reset the default look of the choose and its dropdown half, by utilizing the ::picker() pseudo-element:
choose,
::picker(choose) {
look: base-select;
}
This CSS rule does lots for us: it unlocks full styling capabilities for the whole choose, together with its button, dropdown, and choices. With out this opt-in, you get a regular choose.
Now let’s model the choose, beginning with its button half. First, we’ll eliminate the picker icon by utilizing the brand new ::picker-icon pseudo-element to cover it:
choose::picker-icon {
show: none;
}
Subsequent, let’s add a bit extra kinds to create a nice-looking button:
choose {
background: linear-gradient(
135deg,
rgba(40, 40, 50, 0.4) 0%,
rgba(60, 60, 70, 0.25) 50%,
rgba(50, 50, 60, 0.35) 100%
);
backdrop-filter: blur(12px) saturate(180%);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.2),
inset 0 1px 1px rgba(255, 255, 255, 0.15),
inset 0 -1px 1px rgba(0, 0, 0, 0.1);
border: 1px stable rgba(255, 255, 255, 0.2);
colour: white;
min-inline-size: 12rem;
}
And right here is our new choose button:

Now let’s flip our consideration to the dropdown half since that is the place the magic occurs.
In a choose, the dropdown incorporates all of the choices and seems once you click on on the button. Plenty of browser default kinds apply to it already to set its place, background-color, margin, and extra. So, we’ll need to disable and override a bunch of stuff.
In our demo, we don’t need the dropdown to be seen in any respect. As a substitute, we wish every particular person possibility (every folder on this case) to look as if floating above the web page, with out a container aspect.
To do that, let’s use the ::picker(choose) pseudo-element to set our kinds:
::picker(choose) {
background: clear;
border: none;
box-shadow: none;
overflow: seen;
}
And with this, the dropdown isn’t seen anymore and it not constrains the choices or clips them in the event that they overflow the dropdown space.
This offers us the next enhancements:

It’s now time to show our consideration to the choice parts. First, let’s exchange the checkmark icon with a bit of disc icon as an alternative by utilizing the ::checkmark pseudo-element:
possibility::checkmark {
content material: "●";
colour: #222;
}
This pseudo-element makes it straightforward to alter the form, the colour, and even the scale of the checkmark.
Let’s additionally add an extra pseudo-element to every possibility, by utilizing possibility::earlier than, to show a folder emoji subsequent to every possibility. And, with a pinch extra CSS high-quality tuning, we find yourself with this:

We now have an inventory of folders which floats on prime of the web page once we click on the choose button. It really works like some other choose, too, both with the mouse, or with the keyboard, so we are able to simply thank the browser for sustaining the accessibility of the enter whereas we’re having enjoyable with CSS.
Let’s now apply some CSS transformation to make the stack of folders a bit of curvy, so it seems cooler.
To realize this, we’ll want another piece of latest CSS syntax which, sadly, isn’t but extensively accessible: the sibling-index() perform. This perform returns the index of the aspect inside its siblings. The sibling-count() perform additionally exists, and it returns the whole variety of siblings, however we received’t want it right here.
Getting access to the index of the present aspect inside its siblings signifies that we are able to model every possibility relying on its place throughout the choose dropdown. That is precisely what we have to make the choices seem at a progressively bigger angle.
Right here is the code:
possibility {
--rotation-offset: -4deg;
rotate: calc(sibling-index() * var(--rotation-offset));
}
On this code snippet, we first create a customized property referred to as --rotation-offset, which defines the angle by which every possibility ought to rotate, with respect to the earlier possibility. We then use this with the rotate property, multiplying its worth by sibling-index(). That manner, the primary possibility is rotated by -4 levels, the second by -8 levels, the third by -12 levels, and so forth.
Now, that’s not sufficient by itself to create the phantasm of a curved stack of folders as a result of every folder rotates round its personal level of origin, which is situated within the top-left nook of every folder by default. Proper now, we get this:

Let’s use the transform-origin property to set a shared level of origin round which all choices will rotate. As a result of transform-origin is relative to every particular person aspect, we have to use the sibling-index() perform once more to maneuver all origin factors up and to the best so that they’re all in the identical spot:
possibility {
--rotation-offset: -4deg;
rotate: calc(sibling-index() * var(--rotation-offset));
transform-origin: proper calc(sibling-index() * -1.5rem);
}
And with this, we get the next consequence:

The ultimate step is to animate the choices. It seems nice as it’s, however we wish the stack of folders to get progressively curved till it reaches its closing form. That’ll make it a lore extra energetic and enjoyable to work together with.
Let’s reset the choice’s rotation by default, and apply a transition with a pleasant elastic easing perform:
possibility {
rotate: 0deg;
transition: rotate 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
And now, let’s apply the best rotation angle solely when the choose is open:
choose:open possibility {
rotate: calc(sibling-index() * -1 * var(--rotation-offset));
}
Sadly, the above is just not sufficient. By default, CSS transitions are usually not triggered when a component seems, which is the case for our choices. Fortunately, there’s a repair for this situation: the @starting-style at-rule. This at-rule lets us outline the preliminary state of the choices, making it attainable for the transition to play proper when the choices seem:
@starting-style {
choose:open possibility {
rotate: 0deg;
}
}
Yet one more factor to make it even nicer. Let’s delay every transition relative to the earlier one to make it seem like every folder is available in barely after the one earlier than it. To realize this, let’s use the sibling-index() perform as soon as extra, as a multiplier to a brief transition delay:
possibility {
transition-delay: calc((sibling-index() - 1) * 0.01s);
}
We now have an animated, curved, stack of folders carried out with a aspect! Try the demo and code within the subsequent CodePen:
CSS beneficial properties loads of new capabilities annually. I hope this demo stroll by means of helped you get a greater understanding of a few of these new capabilities. Constructing it helped me perceive loads of new, to me, ideas. It additionally received me very excited in regards to the customizable choose function. A lot, that I created different demos too. So, let’s have a look at two extra of them. This time although, we’ll go faster and solely spotlight an important elements.
Fanned deck of playing cards
For our second demo, we’ll create a card picker, which opens up in a fanned deck vogue:
The HTML markup for this demo is a bit of totally different than for the earlier one. Every card has a little bit of content material to show, so let’s create a few parts to every possibility:
The opposite fascinating factor in regards to the HTML code we’ll use right here, is the addition of an empty aspect proper under the opening tag:
This empty serves a really particular function: it prevents the default habits from taking place.
In a custom-made choose, the browser robotically shows the at present chosen possibility’s content material (on this case, the cardboard face) within the button space of the choose. And it does this by creating a component named which mirrors the chosen possibility. However, in our demo, we wish the button to all the time present the again of the deck of playing cards, not the chosen card. To realize this, we override the default habits by introducing our personal . This tells the browser to not insert its personal aspect and lets us model the aspect:
choose {
background:
/* Diamond sample overlay */
repeating-linear-gradient(45deg,
clear,
clear 1vmin,
rgba(255, 255, 255, 0.05) 1vmin,
rgba(255, 255, 255, 0.05) 2vmin),
repeating-linear-gradient(-45deg,
clear,
clear 1vmin,
rgba(255, 255, 255, 0.05) 1vmin,
rgba(255, 255, 255, 0.05) 2vmin),
/* Base gradient */
linear-gradient(135deg, #8b0000 0%, #dc143c 50%, #8b0000 100%);
}

Now, for the dropdown half, similar to within the earlier demo, we don’t need the dropdown container aspect to be seen, so we’ll additionally override the default background, border, and overflow kinds like we did earlier than.
Extra importantly, the place of the deck of playing cards, when opened, is essential. We wish it to fan out from the deck itself and stay centered above it.
In a customizable choose, the dropdown half, i.e., the ::picker(choose) pseudo-element, is positioned relative to the button half because of anchor positioning, which is nice as a result of we are able to override it!
In our case, let’s override the alignment relative to the anchor, which is the button, by utilizing the position-area property:
::picker(choose) {
position-area: heart heart;
inset: 0;
}
We’re additionally setting the inset property to 0 right here. This units all prime, proper, backside, and left properties to 0 in a single declaration, which makes the dropdown half in a position to make use of the whole accessible area, relatively than being constrained by the browser to look on the facet of the choose button.
Lastly, let’s make the playing cards seem facet by facet, relatively than above one another:
choose:open::picker(choose) {
show: flex;
}
When the choose aspect is open and the choices are seen, we now see this:

The subsequent step is to rotate every card so the choices seem in a fanned out manner, with the middle card straight, the playing cards to the left progressively extra rotated in direction of the left, and the playing cards to the best rotated in direction of the best.
To do that, you’ve guessed it, we’ll use the sibling-index() property once more. We’ll additionally use the sibling-count() property this time:
possibility {
--card-fan-rotation: 7deg;
--card-fan-spread: -11vmin;
--option-index: calc(sibling-index() - 1);
--center: calc(sibling-count() / 2);
--offset-from-center: calc(var(--option-index) - var(--center));
rotate: calc(var(--offset-from-center) * var(--card-fan-rotation));
translate: calc(var(--offset-from-center) * var(--card-fan-spread)) 0;
transform-origin: heart 75vmin;
}
Within the above code snippet, we’re calculating the offset of every card relative to the middle card, and we’re utilizing this to rotate every card by increments of seven levels. For instance, in a deck with 9 playing cards, the left-most card (i.e., the primary card) will get a -4 offset, and will likely be rotated by -4 * 7 = -28 levels, whereas the right-most card will likely be rotated by 28 levels.
We additionally use the translate property to carry the playing cards shut collectively right into a fan, and the `transform-origin` property to make all of it look good.

Lastly, let’s carry all of it collectively by animating the opening of the deck. To do that, we are able to outline a CSS transition on the customized --card-fan-rotation property. Animating it from 0 to 7 levels is all we have to create the phantasm we’re after. Animating a customized property takes a few steps.
First, let’s outline the customized property’s kind, in order that the browser can animate it accurately:
@property --card-fan-rotation {
syntax: '';
inherits: false;
initial-value: 7deg;
}
Second, let’s use a @starting-style at-rule, like within the earlier demo, to permit the CSS transition to play when the choices seem:
@starting-style {
choose:open possibility {
--card-fan-rotation: 0deg;
}
}
Then, set the beginning rotation angle when the choose aspect is closed, and outline the CSS transition:
possibility {
--card-fan-rotation: 0deg;
transition: --card-fan-rotation 0.2s ease-out;
}
And, lastly, let’s set the ultimate angle when the choose is opened:
choose:open possibility {
--card-fan-rotation: preliminary;
}
We will use the `preliminary` worth above as an alternative of hard-coding the 7deg worth once more, because it’s already outlined because the preliminary worth within the @property rule above.
That’s it, our deck of playing cards, with animated opening, is now prepared! Try the entire code and stay demo on this CodePen:
It’s superb to me how far customizable selects mean you can push issues. You don’t solely get to override the way in which the button and its choices look, you get to alter how the whole lot is positioned, and even animated.
Let’s shut with one closing demo.
Radial emoji picker
Similar to within the earlier demo, right here we wish the emojis to be centered across the choose button. To realize this, let’s override the default anchor positioning of the dropdown half.
This time, we’ll use the anchor() perform to set the highest and left coordinates of the dropdown container:
::picker(choose) {
prime: calc(anchor(prime) - var(--radius));
left: calc(anchor(left) - var(--radius));
width: calc(var(--radius) * 2 + var(--option-size));
top: calc(var(--radius) * 2 + var(--option-size));
}
On this code snippet, the --radius property is the radius of the circle of emojis. And, since customizable selects already use anchor positioning, we are able to use the anchor() perform to place the dropdown relative to the button.
Now we have to place the choices in a circle, contained in the dropdown. Because it seems, CSS is aware of trigonometry now, too, so we’ll use the cos() and sin() capabilities along with the sibling-index() and sibling-count() capabilities:
possibility {
place: absolute;
--angle: calc((sibling-index() - 2) * (360deg / (sibling-count() - 1)) - 90deg);
prime: 50%;
left: 50%;
translate:
calc(-50% + cos(var(--angle)) * var(--radius)) calc(-50% + sin(var(--angle)) * var(--radius));
}
And there we’re:

The ultimate demo additionally incorporates a little bit of code for animating the opening of the choices, however we received’t dig into the main points on this article.
To study extra and play with the stay demo, take a look at this CodePen:
Wrapping up
That’s it for now. I hope these demos have given you a bit extra of an understanding for a way customizable selects are custom-made, and a few pleasure for truly utilizing the function in an actual venture.
Remember, even when custom-made, the aspect remains to be a and can work simply high-quality in non-supporting browsers. So, even when the function remains to be in its early days, you should use it as an awesome progressive enhancement.









