Inspiration for Custom Select Elements

Some inspiration for styling a custom version of the select element. There are many possibilities and today we are exploring some ideas of how to let the user select a choice in style.

From our sponsor: Elementor, a design oriented WordPress website builder for pros

Today we’d like to share some inspiration for custom select styles with you. In forms where we’d like to use custom styles for the input elements, we can use JavaScript libraries that transform the HTML elements into a structure that allows us to do some better styling, especially for more complex inputs like the select element. Once a custom structure is in place, the possibilities are really endless and the aim of creating a better experience for the user can be reached more easily.

What kind of style is used depends of course on what is represented and what you want to know from your user using the input element. When replacing the select element with a custom structure it is very important to keep the new element accessible. Providing a label and focus styles are just some of the things you should keep in mind. Read more about some form accessibility in the HTML Techniques for Web Content Accessibility Guidelines 1.0 by the W3C.

For demo purposes, we are using a very raw custom script in our examples where the custom select element can be accessed by i.e. using the TAB key and hitting space. Note that we haven’t provided any substantial focus styles.

Please note that some of the styles are experimental and for the sole purpose of showing what’s possible (in modern browsers).

In the demos we use icons from the following icon sets: Ionicons, Font Awesome, Linecons and Maki.

The SVG flags used in one of the demos are from the Flag Webicons Set by Sean Herron.

The round icons used in one of the demos are from the free Ballicons 2 set by Pixel Buddha.

Let’s take a look at our custom select script. Having a select element like the following

<select class="cs-select cs-skin-rotate">
	<option value="" disabled selected>Choose your option</option>
	<option value="1">Option 1</option>
	<option value="2">Option 2</option>
	<option value="3">Option 3</option>

… we’ll transform it into this structure:

<div class="cs-select cs-skin-rotate">
	<span class="cs-placeholder">Choose your option</span>
	<div class="cs-options">
			<li data-option data-value="1" class="cs-selected"><span>Option 1</span></li>
			<li data-option data-value="2"><span>Option 2</span></li>
			<li data-option data-value="3"><span>Option 3</span></li>
	<select class="cs-select cs-skin-rotate">
		<option value="" disabled selected>Choose your option</option>
		<option value="1">Option 1</option>
		<option value="2">Option 2</option>
		<option value="3">Option 3</option>

We are keeping the actual select element because we’ll actually use it to set the selected value, which in turn will be submitted if we submit a form.

The “placeholder” is recognized by being disabled and having an empty value. It’s not a necessary option, it can be left out and the first option would instead be added to the first list item, or the one that has the selected attribute.

Optionally, we can define a data-link and a data-class in an option of the select element. The link option will allow to actually open a hyperlink when clicking a list item. When custom classes are needed on a list item, the data-class attribute can be used.

The following options are available:

newTab : true,
// open links in new tab (when data-link used in option)

stickyPlaceholder : true,
// when opening the select element, the default placeholder (if any) is shown

onChange : function( val ) { return false; }
// callback when changing the value

The stickyPlaceholder defines if the default placeholder text is shown every time we open the select element.

The basic styles for our examples are in the cs-select.css. Here we define some necessary styles for making the custom select look like a plain dropdown. The specific skin classes need the skin style sheet and an example for a specific skin is the following (border example):

@font-face {
	font-family: 'icomoon';
	src:url('../fonts/icomoon/icomoon.eot?#iefix-rdnm34') format('embedded-opentype'),
		url('../fonts/icomoon/icomoon.woff?-rdnm34') format('woff'),
		url('../fonts/icomoon/icomoon.ttf?-rdnm34') format('truetype'),
		url('../fonts/icomoon/icomoon.svg?-rdnm34#icomoon') format('svg');
	font-weight: normal;
	font-style: normal;

div.cs-skin-border {
	background: transparent;
	font-size: 2em;
	font-weight: 700;
	max-width: 600px;

@media screen and (max-width: 30em) {
	.cs-skin-border { font-size: 1em; }

.cs-skin-border > span {
	border: 5px solid #000;
	border-color: inherit;
	transition: background 0.2s, border-color 0.2s;

.cs-skin-border > span::after,
.cs-skin-border .cs-selected span::after {
	font-family: 'icomoon';
	content: 'e000';

.cs-skin-border ul span::after {
	content: '';
	opacity: 0;

.cs-skin-border .cs-selected span::after {
	content: 'e00e';
	color: #ddd9c9;
	font-size: 1.5em;
	opacity: 1;
	transition: opacity 0.2s;

.cs-skin-border.cs-active > span {
	background: #fff;
	border-color: #fff;
	color: #2980b9;

.cs-skin-border .cs-options {
	color: #2980b9;
	font-size: 0.75em;
	opacity: 0;
	transition: opacity 0.2s, visibility 0s 0.2s;

.cs-skin-border.cs-active .cs-options {
	opacity: 1;
	transition: opacity 0.2s;

.cs-skin-border ul span {
	padding: 1em 2em;
	backface-visibility: hidden;

.cs-skin-border .cs-options li span:hover,
.cs-skin-border li.cs-focus span {
	background: #f5f3ec;

Take a look at the demos and see some examples of how a custom select can be styled.

We hope you enjoy them and find them inspiring!

Tagged with:

Mary Lou

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 109

Comments are closed.
  1. How can i use the slide effect for variable number of items? As i see background transform is fixed: -webkit-transform: scale3d(1.1,3.5,1), what if i have more items. I cannot set ::before selector dynamically 🙁

    Thank you.

  2. Hi, is it possible to do “slide effect” from your demo without javascript?

  3. Hi,
    I really like it!
    I want to do something like this but i don’t really understand it.
    I have a basic knowledge of CSS, HTML, JS and JQuery but don’t know how to start?
    Could anyone help me by styling a custom select box?
    I have the Markup and the CSS but it’s not styled…:/

  4. Hey Mary Lou and thank you very much for this script.
    Just three little things I notice :
    – a semi-colon is missing on selectFx.js, line 133, just before “options += ‘</ul></li>’;” because if you want to minify the script (with javascriptPacker for example) console show an error (; missing before statment). I search a long time to fix this issue. 🙂

    – if you use several select on the same page, option elements of the first one are underneath the second select. To fix the issue, z-index of div.cs-select have to be smaller than z-index of .cs-select.cs-active (for example 100 for the first one and 200 for the second).

    – if the first option is null (or empty), height of this element is smaller than height of the others. To fix the issue, a non-breaking space (&nbsp) have to be used between option tag for the first element (<option value=”0″>&nbsp ;</option>)

    Thanks a lot again.


    • Hi!
      How did you manage to have several selects (i tried the “slide” version) on one page?
      When I have 2 or more included, they double their size an break the page 🙁

  5. Hello, Mari!
    I need a big help. I’m having trouble adding a link within the option tag. <a href rel=”nofollow”> tag to add or change the value and nothing happens. What can I do?

  6. Hey ! Thx a lot for your work. I appreciate it a lot. I have some trouble with the “data-link” attribute. It always open a new tab :/

  7. Thank you so much for all the hard awesome work you do!
    I have a weird problem using the first select type: I’m trying to use jquery on change of the select to do some other stuff, but I noticed that it doesn’t work if I use the customized css select.
    $('#divID').on('change', '#selectID', function() {

    It is of course working fine , but If I use it on the customized select it won’t work!
    Guess it’s because of some javascript code used by the select, but I can’t figure it out why!
    Any ideas ? Thanks in advance

  8. Hi Mary!

    I’m trying to turn the “slide” select into an AngularJS directive. It works great so far, but as soon as I have more than one select on the page, it breaks.
    For making sure I didn’t screw up with my directive I tried putting 2 slide select elements on one page, and it broke as well.
    Do you have any idea why we can’t have multiple slide selects on one page?
    I’d be very happy about input from you genius! 🙂

    take care,

  9. I’ve created a small jQuery port for this for everyone willing to use jQuery instead of loading classie.js. It’s on my GitHub.

    If you need more of these, let me know.

    • In case anyone tried to use it, it had a bug which is now fixed, and the port is tested and properly working. Sorry about the hiccup.

  10. i’m used this script and it’s not working for me, not simple, not ajax)

    I’m edit selectFx.js
    ~300 stroke, before callback paste

    var val1 = this.selPlaceholder.textContent;
    var idCheck = $(‘select:has(option:contains(‘+val1+’))’).attr(‘id’);

    and after // callback this.options.onChange( this.el.value );

    insert this: $(‘#’+idCheck+”).trigger(‘change’);