Welcome to a tutorial on how to create a custom dropdown arrow using pure CSS and HTML. Yes, we can pretty much do any customization with modern HTML and CSS. But strangely, there is no straightforward way to customize a dropdown arrow in pure CSS.
To create a custom dropdown arrow:
- Wrap the select box –
<div class="sel"><select><option>Demo</option></select></div>
- Hide the default arrow –
.sel select { apperance: none }
- Create a custom arrow with HTML symbol –
.sel::after { content: "\25b6" }
- Position the custom arrow –
.sel { position: relative } .sel::after { position: absolute; top: 0; right: 0 }
That covers the basic mechanics, but let us walk through a detailed example in this guide – Read on!
ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.
TLDR – QUICK SLIDES
[web_stories_embed url=”https://code-boxx.com/web-stories/customized-dropdown-arrow-with-css/” title=”Customized Dropdown Arrow With CSS” poster=”https://code-boxx.com/wp-content/uploads/2022/03/STORY-HTML-20230505.webp” width=”360″ height=”600″ align=”center”]
Fullscreen Mode – Click Here
TABLE OF CONTENTS
DOWNLOAD & DEMO
Firstly, here is the download link to the example code as promised.
QUICK NOTES
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.
EXAMPLE CODE DOWNLOAD
Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
THE DEMO
PURE CSS CUSTOM DROPDOWN
All right, let us now dive into the example of how to customize a dropdown using pure CSS only.
PART 1) HTML – WRAP THE SELECT BOX
<div class="sel"><select>
<option>Good Boy Doge</option>
<option>Evil Cate</option>
<option>Sneezing Panda</option>
<option>Confession Bear</option>
<option>Fabulous Llama</option>
</select></div>
No sweat. All we need in the HTML is to wrap a normal <select>
within a <div>
wrapper.
PART 2) CUSTOM HTML ARROW SYMBOL
/* (A) BASICS - HIDE DEFAULT + SHOW CUSTOM ARROW */
.sel select { appearance: none; }
.sel::after { content: "\25b6"; }
/* (B) DIMENSIONS */
/* (B1) WRAPPER - OPTIONAL */
.sel { max-width: 400px; margin: 10px; }
/* (B2) "EXPAND" SELECT BOX */
.sel select {
width: 100%; padding: 10px;
color: #333;
border: 1px solid #cfcfcf;
}
Now, here comes the irritating part – CSS does not have a property to set the dropdown arrow, we have to do it through “alternative means”.
- (A1) Hide the default dropdown arrow using
appearance: none
. - (A1) Use an HTML symbol to create our own custom arrow –
.sel::after { content: "\CODE"; }
. I will leave a link to a list of HTML symbols in the extras section below. - (B) “Expand” the
<select>
box withwidth: 100%
, and make it fill up the<div>
container.
PART 3) POSITIONING THE ARROW
/* (C) POSITION CUSTOM ARROW */
/* (C1) REQUIRED FOR ABSOLUTE POSITION BELOW */
.sel { position: relative; }
/* (C2) DEFAULT - ARROW ON RIGHT SIDE */
.sel::after {
position: absolute;
top: 50%; right: 10px;
transform: translateY(-50%);
}
/* (C3) ARROW ON LEFT SIDE */
.left.sel::after { left: 10px; right: auto; }
.left.sel select { padding-left: 30px; }
To properly position the arrow:
- (C1) It is necessary to set the
<div>
container toposition: relative
. - (C2) Setting
position: absolute; top: 50%; right: N
will “push” the arrow to the right side of the<div>
container. - (C2) Take note,
top: 50%
will not “accurately vertical center” the arrow. It is necessary to addtranslateY(-50%)
to do that. - (C3) If you want the arrow to be on the left side, just set
left: Npx; right: auto
.
EXTRA) COSMETICS
/* (D) COSMETICS */
/* (D1) CUSTOM ARROW IS ESSENTIALLY TEXT! */
.sel::after { font-size: 16px; color: #aaa; }
/* (D2) ROTATE ARROW ON HOVER */
.sel::after { transition: all 0.3s; }
.sel:hover::after {
transform: translateY(-50%) rotate(90deg);
color: #ff1212;
}
Finally, some optional cosmetics.
- (D1) The HTML arrow symbol is still text. We can apply color and font size to it.
- (D2) Using CSS
transition
androtate
, we can easily add a “rotate on mouse hover” animation.
EXTRA BITS & LINKS
That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.
COMPATIBILITY CHECKS
- CSS Translate – CanIUse
- CSS Rotate – CanIUse
This example will work on all “Grade A” modern browsers.
CAN WE CUSTOMIZE THE DROPDOWN OPTIONS?
- No, not exactly. Some CSS properties do work on
<option>
, but every browser renders the<select><option>
differently. - On a desktop, the selectable options will be below the box.
- But on mobile, it will probably become a popup instead.
The only way to create a “fully customized dropdown box” is to “entirely customize it”, and “make it from scratch”.
LINKS & REFERENCES
- HTML Symbols – Toptal
- Example on CodePen – Custom Dropdown Arrow With Pure CSS
TUTORIAL VIDEO
INFOGRAPHIC CHEAT SHEET
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you with your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!
Hi
I want to add a three dot loading indicator for select icon while options are being loaded. Can you guide me?
1) Study AJAX
2) While loading – Disable dropdown and show “now loading”
3) On loaded – Enable dropdown and show “dropdown arrow”
Otherwise, I will take this as a request for a new tutorial. Good luck.
https://code-boxx.com/faq/#help “Requests for new features and tutorials may be considered, but will not be immediately answered”
Hi
Thank you for this quick and easy method. It helped me and one thing that I added was the z-index so clicking the arrow “seem” to activate the dropdown:
simply added :
.cselect select { z-index: 2; }
.cselect::after { z-index: 1; }
Thanks again!
Hello,
Would it be possible to add support for a scrollbar if there are many items in the list?
No, there’s no CSS to directly control it. Also on mobile browsers, this will probably be rendered differently as a scrollable popup list.