56

I have a select element and am using the first option as the title of the select field. I am wondering if there is a way to gray out the text inside the select field when the first option is selected. Can this only be done in JS, or is there a CSS solution?

I have tried changing the style of the first option but that only changes the colour of the text when I activate the dropdown menu.

<select>
  <option>Please select your favourite fruit</option>
  <option>Apple</option>
  <option>Banana</option>
</select>
Jon
  • 8,205
  • 25
  • 87
  • 146

5 Answers5

90

Here is a more modern solution so it's not specific to the first option, but rather an invalid option and requires no JS to show only the title/placeholder option as grey whereas the rest appear normal.

select,
select option {
  color: #000000;
}

select:invalid,
select option[value=""] {
  color: #999999;
}

label {
  display: block;
  margin: 16px 0;
}

/*Added for browser compatibility*/
[hidden] {
  display: none;
}
<label>
    Invalid option cannot be selected and is hidden from the user in the dropdown.
    <select required>
      <option value="" selected disabled hidden>Please select your favourite fruit</option>
      <option>Apple</option>
      <option>Banana</option>
    </select>
</label>

<label>
    Invalid option cannot be selected, but is not hidden from the user in the dropdown.
    <select required>
      <option value="" selected disabled>Please select your favourite fruit</option>
      <option>Apple</option>
      <option>Banana</option>
    </select>
</label>

<label>
    Invalid option can be selected and is not hidden from the user in the dropdown.
    <select required>
      <option value="" selected>Please select your favourite fruit</option>
      <option>Apple</option>
      <option>Banana</option>
    </select>
</label>

The :invalid selector on the select only works on an option if the select box is required and the selected option's value is empty, so you can style it as you would a text box's placeholder text.

Setting it to disabled prevents the user from selecting it in the select's options, and setting it to hidden hides it from the select's options.

Here is my CodePen demo that explores additional select box styles and shows this one in action on a light background.

AuRise
  • 2,253
  • 19
  • 33
  • 3
    This worked perfectly for me, and is a super clean solution! – Nick Litwin Mar 06 '17 at 20:26
  • 1
    Thanks Tessa, using `:invalid` is an excellent solution, worked perfectly for my use-case too. :) – chrisheninger Apr 20 '17 at 03:19
  • `:invalid` makes all option grey if the value is empty. This is not a clean solution. – jstice4all Sep 13 '17 at 09:33
  • @jstice4all can you show me the HTML and CSS you're using? In my CodePen demo I linked to in the answer, it does not cause all of the options to appear grey when they are selected. Only the invalid option appears grey when selected. – AuRise Sep 15 '17 at 16:46
  • Ah, I saw what you mean. When you use just without setting the value="", they also appeared grey in the drop-down. I've updated my answer to fix that. – AuRise Sep 15 '17 at 16:54
  • 3
    I like this solution a lot, Tessa! Since my answer is almost 5 years old and this one is much better to solve the problem and uses only CSS, I'm gonna edit mine and point to this one. – Fábio Duque Silva Sep 19 '17 at 14:40
  • @AllanRaquin Did you try the CodePen demo in the same browser/OS? http://codepen.io/TessaWatkins/pen/bwymaY – AuRise Jan 11 '18 at 14:14
  • @Tessa Yes I tried and found that the normalize.css is absolutely necessary to make it works. Something is probably missing in the in the answer's stylesheet to make it work as a standalone solution. But didn't find what :/ – Allan Raquin Jan 11 '18 at 14:18
  • Ah, I see normalize.css includes "[hidden], template{ display: none; }", which is why the first option with the "hidden" attribute would not appear, but it's also in my user agent sylesheet as "option[Attributes Style]", so perhaps that browser doesn't include that CSS by default. Good catch! Did the font still appear as grey? Or was it that it just wasn't being hidden? – AuRise Jan 11 '18 at 14:48
  • @AllanRaquin I added that CSS to the answer snippet. Try again and let me know if that resolved your problem. – AuRise Jan 11 '18 at 14:50
  • 1
    @Tessa First, thanks for your efforts ! In fact the first option was already hidden in the previous version. It's my fault I didn't specified what wasn't working, the problem is the color. In the snippet it's always set to black, even with in the new version. But it works in the codepen with the 2 last select, (and only with the normalize). Here the simplified version of the working codepen: https://codepen.io/anon/pen/opdxZE?editors=1100 (so still with the normalize.css) – Allan Raquin Jan 11 '18 at 15:07
  • Wasn't able to get the option[value=""] to work all the way. (Using a dark background) In the options list the text is grey, but the selected option color is still white even when it's the intended place holder. I have select set to white, and select option set to white, then with option[value=""] set to grey below both of them in the style sheet. Select select is still white (using vanilla css) – Zack Plauché Jun 29 '20 at 12:29
  • @ZackPlauché If you're doing a lot of style customization with a select field, especially with the drop-down menu's appearance, I recommend using an HTML/JS alternative to the native element because browsers and mobile devices do not display them consistently. – AuRise Jun 30 '20 at 18:35
  • @Tessa that makes a lot of sense! Thanks for the response :) – Zack Plauché Jul 01 '20 at 09:57
  • @ZackPlauché No problem! It can be quite frustrating trying to style a select field and make it appear consistent in all browsers/devices. I think my phone doesn't even display the drop-down, it just pulls the options up in it's own UI scroll wheel at the bottom. No CSS on the `option` element is going to change that! – AuRise Jul 01 '20 at 15:25
  • 1
    In Safari I notice the top example doesn't do the hiding. Seems it's just a fun safari inconsistency: https://stackoverflow.com/a/15025961/338265 – Harry Wood Jul 09 '20 at 00:17
  • You'll want to add :not(:disabled) to the 'select option' in the CSS if you have other disabled options besides the first – Tom Winch Jun 22 '21 at 13:51
  • FOR ANGULAR USERS: This solution worked, but you have to adapt it slightly. Instead of using `:invalid` you have to use `.ng-invalid` at the end of the element. Then you don't even need the `[value=""]` specification. – MikhailRatner Nov 08 '21 at 13:34
  • why it does not work here ? https://codepen.io/sandeshsapkota/pen/qBYOVEQ @AuRise – Sandesh Sapkota Sep 07 '22 at 07:53
  • @SandeshSapkota because in your CSS, you've defined them both as red – AuRise Sep 08 '22 at 23:32
42

September 2017 edit

You should take a look at Tessa's answer below, since it's CSS only and much better now! This answer is almost 5 years old now, so things have changed a bit. I'm keeping the original answer just for reference.

Original answer

I am closer to what you need:

You need to gray the entire SELECT (so that when it's closed, it is gray), then "un-gray" all the OPTION's (put them black) and gray the first-child. Something like this:

CSS

select
{
    color: #ccc;
}
option
{
    color: #000;
}
option:first-child
{
    color: #ccc;
}

EDIT So the edited code is:

HTML

<select onchange="changeMe(this)">
  <option selected disabled>Please select your favourite fruit</option>
  <option>Apple</option>
  <option>Banana</option>
</select>

Javascript

<script type="text/javascript">
    function changeMe(sel)
    {
      sel.style.color = "#000";              
    }
</script>

I've update jsFiddle. You can check it here: http://jsfiddle.net/s5Xy2/5/

Notice that I've also changed the HTML part, because I think you want to use the "disabled" attribute (and because of that, you'll have to add the "selected" attribute also).

If you still want the pure CSS code, it's here: http://jsfiddle.net/s5Xy2/4/

Fábio Duque Silva
  • 2,146
  • 1
  • 18
  • 16
  • Thank you. I think this is the furthest you can go with pure CSS. I'll consider if it is worth using Javascript to achieve a visual effect. Thanks :) – Jon Dec 04 '12 at 17:15
  • Actually using JS to achieve what you want won't add much more complexity. I'll throw you an example in a couple of minutes... – Fábio Duque Silva Dec 04 '12 at 17:17
  • @vsync Well, the OP asked «Can this only be done in JS, or is there a CSS solution?» to which I gave the most approximate CSS-only solution I know. Then (and it's labeled as an edit), I also gave him a minimal JS solution. If you find a better, CSS-only solution, please do tell me. :) – Fábio Duque Silva May 13 '14 at 16:22
  • Can't select first (gray) item back after selecting some other item in JS example. All items are gray when selected in CSS example. – denis.peplin Feb 11 '15 at 06:33
  • Worked for me, but throws an exception as soon as you select a valid item: ReferenceError: changeMe is not defined at HTMLSelectElement.onchange – xabi_sides Sep 11 '17 at 12:18
  • @wickedchild Take a look at where you defined the `changeMe` function. It's probably defined in an incorrect place and it's not on the global scope. Did you take a look at the jsfiddle example? – Fábio Duque Silva Sep 12 '17 at 13:24
5

Inspired from Fábio Silva's solution, a very cool solution using AngularJS:

select {
  color: #ccc;
}
option {
  color: #aaa;
}
option:first-child {
  color: #ccc;
}
select.ng-dirty {
  color: #aaa;
}
paulld
  • 151
  • 2
  • 5
0

You can edit your code to my code :

<select id="drop">
  <option>Please select your favourite fruit</option>
  <option>Apple</option>
  <option>Banana</option>
</select>
<style type="text/css">
#drop :first-child
{
color:gray;
}
</style>

This code set first item color gray .

i hope help you...

A1Gard
  • 4,070
  • 4
  • 31
  • 55
  • 2
    This only grays out the first child when you open/activate the dropdown. I think that @icu222much wants it to be grayed, even with the dropdown closed (but only when the first item is selected) – Fábio Duque Silva Dec 04 '12 at 01:36
  • Hey man this code worked on IE , for complete do he what need use java script , i ask him for update answer... – A1Gard Dec 04 '12 at 09:13
  • @MahdiParsa I am looking for a non javascript/jQuery solution. – Jon Dec 04 '12 at 16:45
  • @FábioSilva You are correct. I want the first select option be gray even when the dropdown is closed. – Jon Dec 04 '12 at 16:46
0

Here's my 2018 version that combines some of the other answers and a bit of my own js. There does not seem to be a solution that works w/o javascript if you want the first element gray when it is closed.

var grayout = document.getElementsByClassName('grayout');

var grayOutSelect = function() {
    if ( this.value === "" ) {
        this.classList.add('gray');
    } else {
        this.classList.remove('gray');
    }
};

for (var i = 0; i < grayout.length; i++) {
    grayout[i].addEventListener('change', grayOutSelect);
    if ( grayout[i].value === "" ) {
        grayout[i].classList.add('gray');
    } else {
        grayout[i].classList.remove('gray');
    }
}
select {
  color: #333;
}
select.gray {
  color: #aaa;
}

/* Optional styles for when the select is open. Doesn't work on all browsers */
option {
  color: black;
}
.grayout option:first-child {
  color: gray;
}


/* Extra / just to make the demo look nice */
body {
  background: #ddd;
  padding: 30px;
  font-size: 20px;
}
select {
  margin: 0;
  vertical-align: top;
  padding: 5px 60px 5px 8px;
  background-color: #fff;
  background-image: url('https://upload.wikimedia.org/wikipedia/commons/4/4b/Feather-arrows-chevron-down.svg');
  background-position: 97% center;
  background-position: right 8px center;
  background-repeat: no-repeat;
  background-size: 18px;
  border: 2px solid #999;
  border-radius: 3px;
  -webkit-appearance: button;
  -webkit-border-radius: 3px;
  -webkit-padding-end: 30px;
  -webkit-padding-start: 8px;
  -webkit-user-select: none;
  -moz-appearance: none;
  font-size: inherit;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: border 300ms;
}
<p>main example</p>
<p>
  <select class="grayout">
    <option value="">Please select your favourite fruit</option>
    <option value="apple">Apple</option>
    <option value="banana">Banana</option>
  </select>
</p>
<p>one of the real options is selected</p>
<p>
  <select class="grayout">
    <option value="">Please select your favourite computer</option>
    <option value="apple" selected>Apple</option>
    <option value="c64">Commodore 64</option>
    <option value="gateway2000">Gateway 2000</option>
  </select>
</p>
<p>the grayout style is not applied here</p>
<p>
  <select>
    <option value="">Please select your favourite insult</option>
    <option value="jerk">Jerk</option>
    <option value="ahole">A**hole</option>
    <option value="shakespeare">Thou damned and luxurious mountain goat</option>
  </select>
</p>
squarecandy
  • 4,894
  • 3
  • 34
  • 45