[html] How do I make a placeholder for a 'select' box?

I'm using placeholders for text inputs which is working out just fine. But I'd like to use a placeholder for my selectboxes as well. Of course I can just use this code:

<select>
    <option value="">Select your option</option>
    <option value="hurr">Durr</option>
</select>

But the 'Select your option' is in black instead of lightgrey. So my solution could possibly be CSS-based. jQuery is fine too.

This only makes the option grey in the dropdown (so after clicking the arrow):

option:first {
    color: #999;
}

The question is: How do people create placeholders in selectboxes? But it has already been answered, cheers.

And using this results in the selected value always being grey (even after selecting a real option):

select {
    color: #999;
}

This question is related to html css html-select placeholder

The answer is


Here is a CSS solution that works beautifully. The content is added (and absolutely positioned relative to the container) after the containing element (via :after pseudo-class).

It gets its text from the placeholder attribute that I defined where I used the directive (attr(placeholder)). Another key factor is pointer-events: none - this allows clicks on the placeholder text to pass through to the select. Otherwise it won't drop down if the user clicks the text.

I add the .empty class myself in my select directive, but normally I find that angular adds/removes .ng-empty for me (I assume it's because I'm injecting version 1.2 of Angular in my code sample).

(The sample also demonstrates how to wrap HTML elements in AngularJS to create your own custom inputs)

_x000D_
_x000D_
var app = angular.module("soDemo", []);_x000D_
app.controller("soDemoController", function($scope) {_x000D_
  var vm = {};_x000D_
  vm.names = [{_x000D_
      id: 1,_x000D_
      name: 'Jon'_x000D_
    },_x000D_
    {_x000D_
      id: 2,_x000D_
      name: 'Joe'_x000D_
    }, {_x000D_
      id: 3,_x000D_
      name: 'Bob'_x000D_
    }, {_x000D_
      id: 4,_x000D_
      name: 'Jane'_x000D_
    }_x000D_
  ];_x000D_
  vm.nameId;_x000D_
  $scope.vm = vm;_x000D_
});_x000D_
_x000D_
app.directive('soSelect', function soSelect() {_x000D_
  var directive = {_x000D_
    restrict: 'E',_x000D_
    require: 'ngModel',_x000D_
    scope: {_x000D_
      'valueProperty': '@',_x000D_
      'displayProperty': '@',_x000D_
      'modelProperty': '=',_x000D_
      'source': '=',_x000D_
    },_x000D_
    link: link,_x000D_
    template: getTemplate_x000D_
  };_x000D_
  return directive;_x000D_
_x000D_
_x000D_
  /////////////////////////////////_x000D_
  function link(scope, element, attrs, ngModelController) {_x000D_
    init();_x000D_
    return;_x000D_
_x000D_
_x000D_
    ///////////// IMPLEMENTATION_x000D_
_x000D_
    function init() {_x000D_
      initDataBinding();_x000D_
    }_x000D_
_x000D_
_x000D_
    function initDataBinding() {_x000D_
      ngModelController.$render = function() {_x000D_
        if (scope.model === ngModelController.$viewValue) return;_x000D_
        scope.model = ngModelController.$viewValue;_x000D_
      }_x000D_
_x000D_
      scope.$watch('model', function(newValue) {_x000D_
        if (newValue === undefined) {_x000D_
          element.addClass('empty');_x000D_
          return;_x000D_
        }_x000D_
        element.removeClass('empty');_x000D_
        ngModelController.$setViewValue(newValue);_x000D_
      });_x000D_
    }_x000D_
  }_x000D_
_x000D_
_x000D_
  function getTemplate(element, attrs) {_x000D_
    var attributes = [_x000D_
      'ng-model="model"',_x000D_
      'ng-required="true"'_x000D_
    ];_x000D_
_x000D_
    if (angular.isDefined(attrs.placeholder)) {_x000D_
      attributes.push('placeholder="{{placeholder}}"');_x000D_
    }_x000D_
_x000D_
    var ngOptions = '';_x000D_
_x000D_
    if (angular.isDefined(attrs.valueProperty)) {_x000D_
      ngOptions += 'item.' + attrs.valueProperty + ' as ';_x000D_
    }_x000D_
_x000D_
    ngOptions += 'item.' + attrs.displayProperty + ' for item in source';_x000D_
    ngOptions += '"';_x000D_
    attributes.push('ng-options="' + ngOptions + '"');_x000D_
_x000D_
    var html = '<select ' + attributes.join(' ') + '></select>';_x000D_
_x000D_
    return html;_x000D_
  }_x000D_
});
_x000D_
so-select {_x000D_
  position: relative;_x000D_
}_x000D_
_x000D_
so-select select {_x000D_
  font-family: 'Helvetica';_x000D_
  display: inline-block;_x000D_
  height: 24px;_x000D_
  width: 200px;_x000D_
  padding: 0 1px;_x000D_
  font-size: 12px;_x000D_
  color: #222;_x000D_
  border: 1px solid #c7c7c7;_x000D_
  border-radius: 4px;_x000D_
}_x000D_
_x000D_
so-select.empty:before {_x000D_
  font-family: 'Helvetica';_x000D_
  font-size: 12px;_x000D_
  content: attr(placeholder);_x000D_
  position: absolute;_x000D_
  pointer-events: none;_x000D_
  left: 6px;_x000D_
  top: 3px;_x000D_
  z-index: 0;_x000D_
  color: #888;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>_x000D_
_x000D_
<div ng-app="soDemo" ng-controller="soDemoController">_x000D_
  <so-select value-property="id" display-property="name" source="vm.names" ng-model="vm.nameId" placeholder="(select name)"></so-select>_x000D_
</div>
_x000D_
_x000D_
_x000D_


You can do this without using Javascript using only HTML You need to set default select option disabled="" and selected="" and select tag required="". Browser doesn't allow user to submit the form without selecting an option.

<form action="" method="POST">
    <select name="in-op" required="">
        <option disabled="" selected="">Select Option</option>
        <option>Option 1</option>
        <option>Option 2</option>
        <option>Option 3</option>
    </select>
    <input type="submit" value="Submit">
</form>

Because of the diverse styling and functionality between answers provided in this thread, the table of below clarifies the styling and applicable form logic for each of the HTML, HTML+CSS and HTML+CSS+Javascript solutions provided.

I've had to use code formatting because tables aren't permitted in markup, for some reason.
A HTML table will be provided using the code snippet to work around the table restriction.

I've marked this post as community wiki so anyone can detail new posts, though please add JQuery, React, Angular, CoffeeScript, etc, to an alternate post to keep this table simple.

         | Technologies |                                                                Styling                                                                |
  Post   | CSS | Java-  | Select: Placeholder |  Select: valid option  |                  Option: placeholder                    |     Option: valid option     |
   ID    |     | script | Color |  Validation | Color |    Required    | Visibility | Selectable | Color |   Cond. formatting    | Color |   Cond. formatting   |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
41167307 | No  |   No   | Black |   Invalid   | Black |      Yes       |  Visible   |     No     | Grey  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
50200912 | No  |   No   | Black |    Valid    | Black |       No       | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
5859221  | No  |   No   | Black |    Valid    | Black |       No       |  Visible   |     No     | Grey  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
38120777 | No  |   No   | Black |    Valid    | Black |       No       | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
54860799 | Yes |   No   | Grey  |   Invalid   | Black |      Yes       | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
52661024 | Yes |   No   | Grey  |   Invalid   | Black |      Yes       | Invisible  |    N/A     |  N/A  |          No           | Black | select:invalid{Grey} |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
8442831  | Yes |   No   | Grey  |   Invalid   | Black |      Yes       | Invisible  |    N/A     |  N/A  |          No           | Black | select:invalid{Grey} |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
29806043 | Yes |   No   | Grey  |   Invalid   | Black |      Yes       | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
61966461 | Yes |   No   | Grey  |   Invalid   | Black |      Yes       | Invisible  |    N/A     |  N/A  | select:valid{visible} | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
44406771 | Yes |   No   | Grey  |   Invalid   | Grey  |      No        |  Visible   |     No     | Grey  |          No           | Black | select:invalid{Grey} |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
40603035 | Yes |   No   | Black |    Valid    | Black |      No        | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
22994211 | Yes |   No   | Grey  |    Valid    | Black |      No        | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
21722343 | Yes |   No   | Grey  |    Valid    | Grey  |      No        | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
48960650 | Yes |  Yes   | Grey  |   Invalid   | Black |      No        | Invisible  |    N/A     |  N/A  |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
5805194  | Yes |  Yes   | Grey  |    Valid    | Black |      No        |  Visible   |    Yes     | Black |          No           | Black |          No          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
50840409 | Yes |  Yes   | Grey  |    Valid    | Black |      Yes       |  Visible   |    Yes     | Grey  |          No           | Black |          No          |

Solution for Angular 2

Create a label on top of the select

<label class="hidden-label" for="IsActive"
    *ngIf="filterIsActive == undefined">Placeholder text</label>
<select class="form-control form-control-sm" type="text" name="filterIsActive"
    [(ngModel)]="filterIsActive" id="IsActive">
    <option value="true">true</option>
    <option value="false">false</option>
</select>

and apply CSS to place it on top

.hidden-label {
    position: absolute;
    margin-top: .34rem;
    margin-left: .56rem;
    font-style: italic;
    pointer-events: none;
}

pointer-events: none allows you to display the select when you click on the label, which is hidden when you select an option.


I just stumbled across this question, and here's what works in Firefox and Chrome (at least):

_x000D_
_x000D_
<style>_x000D_
select:invalid { color: gray; }_x000D_
</style>_x000D_
<form>_x000D_
<select required>_x000D_
    <option value="" disabled selected hidden>Please Choose...</option>_x000D_
    <option value="0">Open when powered (most valves do this)</option>_x000D_
    <option value="1">Closed when powered, auto-opens when power is cut</option>_x000D_
</select>_x000D_
</form>
_x000D_
_x000D_
_x000D_

The Disabled option stops the <option> being selected with both mouse and keyboard, whereas just using 'display:none' allows the user to still select via the keyboard arrows. The 'display:none' style just makes the list box look 'nice'.

Note: Using an empty value attribute on the "placeholder" option allows validation (required attribute) to work around having the "placeholder", so if the option isn't changed, but is required, the browser should prompt the user to choose an option from the list.

Update (July 2015):

This method is confirmed working in the following browsers:

  • Google Chrome - v.43.0.2357.132
  • Mozilla Firefox - v.39.0
  • Safari - v.8.0.7 (the placeholder is visible in dropdown, but it is not selectable)
  • Microsoft Internet Explorer - v.11 (Placeholder is visible in dropdown but is not selectable)
  • Project Spartan - v.15.10130 (the placeholder is visible in dropdown, but it is not selectable)

Update (October 2015):

I removed the style="display: none" in favour of HTML5 attribute hidden which has wide support. The hidden element has similar traits as display: none in Safari, Internet Explorer, (Project Spartan needs checking) where the option is visible in dropdown, but it is not selectable.

Update (January 2016):

When the select element is required it allows use of the :invalid CSS pseudo-class which allows you to style the select element when in its "placeholder" state. :invalid works here because of the empty value in the placeholder option.

Once a value has been set, the :invalid pseudo-class will be dropped. You can optionally also use :valid if you so wish.

Most browsers support this pseudo-class. Internet Explorer 10 and later. This works best with custom styled select elements; in some cases i.e. (Mac in Chrome / Safari) you'll need to change the default appearance of the select box so that certain styles display, i.e., background-color and color. You can find some examples and more about compatibility at developer.mozilla.org.

Native element appearance Mac in Chrome:

Select box native Mac in Chrome

Using altered border element Mac in Chrome:

Altered select box Mac in Chrome


I just added a hidden attribute in an option like below. It is working fine for me.

_x000D_
_x000D_
<select>_x000D_
  <option hidden>Sex</option>_x000D_
  <option>Male</option>_x000D_
  <option>Female</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


Building upon MattW's answer, you can make the select placeholder option visible in the drop-down menu after a valid selection has been made, by conditionally hiding it only while the placeholder remains selected (and the select is therefore :invalid).

_x000D_
_x000D_
select:required:invalid {_x000D_
  color: gray;_x000D_
}_x000D_
select:invalid > option[value=""][disabled] {_x000D_
  display: none;_x000D_
}_x000D_
option {_x000D_
  color: black;_x000D_
}
_x000D_
<select required>_x000D_
    <option value="" disabled selected>Select something...</option>_x000D_
    <option value="1">One</option>_x000D_
    <option value="2">Two</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


There isn't any need for any JavaScript or CSS, just three attributes:

<select>
    <option selected disabled hidden>Default Value</option>
    <option>Value 1</option>
    <option>Value 2</option>
    <option>Value 3</option>
    <option>Value 4</option>
</select>

It doesn't show the option at all; it just sets the option's value as the default.

However, if you just don't like a placeholder that's the same color as the rest, you can fix it inline like this:

<!DOCTYPE html>
<html>
    <head>
        <title>Placeholder for select tag drop-down menu</title>
    </head>

    <body onload="document.getElementById('mySelect').selectedIndex = 0">
        <select id="mySelect" onchange="document.getElementById('mySelect').style.color = 'black'"     style="color: gray;    width: 150px;">
          <option value="" hidden>Select your beverage</option> <!-- placeholder -->
          <option value="water" style="color:black" >Water</option>
          <option value="milk" style="color:black" >Milk</option>
          <option value="soda" style="color:black" >Soda</option>
        </select>
    </body>
</html>

Obviously, you can separated the functions and at least the select's CSS into separate files.

Note: the onload function corrects a refresh bug.


See this answer :

<select>
        <option style="display: none;" value="" selected>SelectType</option>
        <option value="1">Type 1</option>
        <option value="2">Type 2</option>
        <option value="3">Type 3</option>
        <option value="4">Type 4</option>
</select>

You need form validation and modern browsers offer this from scratch.

So you do not need to take care that the user can not select the field. Because when he is doing it, the browser validation will tell him, that this is a wrong selection.

The browser built in validation function checkValidity().

Bootstrap has there a nice example as well.

HTML

<form class="needs-validation">
  <select required>
    <option value="">Please select an option</option>
    <option value="1">Foo</option>
    <option value="2">Bar</option>
  </select>
<form>

Javascript

form = document.getElementByClassName('needs-validation');
if(form.checkValidity() === true) {
  //form validation succeeded
} else {
  //form validation failed
}

I love the accepted solution, and it works great without JavaScript.

I just want to add how I adopted this answer for a controlled-select React Component, because it took me a few tries to figure it out. It would be really simple to incorporate react-select and be done with it, but unless you need the amazing functionality this repository provides, which I don't for the project in question, there is no need to add any more kilobytes to my bundle. Note, react-select handles placeholders in selects through a complex system of various inputs and html elements.

In React, for a controlled component, you cannot add the selected attribute to your options. React handles the state of the select via a value attribute upon the select itself, along with a change handler, where the value should match one of the value attributes within the options themselves.

Such as, for example

<select value={this.state.selectValue} onChange={this.handleChange} required={true}>
    {options}
</select>

Since it would be improper and in fact would throw an error to add the selected attribute to one of the options, what then?

The answer is simple once you think about it. Since we want our first option to be selected as well as disabled and hidden, we need to do three things:

  1. Add the hidden and disabled attribute to the first defined option.
  2. Set the value of the first option to be an empty string.
  3. Initialize the value of the select to also be an empty string.
state = { selectValue = "" } // State or props or their equivalent

// In the render function
<select value={this.state.selectValue} onChange={this.handleChange} required={true}>
    <option key="someKey" value="" disabled="disabled" hidden="hidden">Select from Below</option>
    {renderOptions()}
</select>

Now you can style the select as indicated above (or via a className if you prefer).

select:invalid { color: gray; }

Input [type="text"] Style Placeholder for Select Elements

The following solution simulates a placeholder as it relates to an input[type="text"] element:

_x000D_
_x000D_
$('.example').change(function () {
  $(this).css('color', $(this).val() === '' ? '#999' : '#555');
});
_x000D_
.example {
  color: #999;
}

.example > option {
  color: #555;
}

.example > option[value=""] {
  color: #999;
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<select class="example">
  <option value="">Select Option</option>
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</select>
_x000D_
_x000D_
_x000D_


Here is mine:

_x000D_
_x000D_
select:focus option.holder {_x000D_
  display: none;_x000D_
}
_x000D_
<select>_x000D_
    <option selected="selected" class="holder">Please select</option>_x000D_
    <option value="1">Option #1</option>_x000D_
    <option value="2">Option #2</option>_x000D_
_x000D_
</select>
_x000D_
_x000D_
_x000D_


I couldn't get any of these to work currently, because for me it is (1) not required and (2) need the option to return to default selectable. So here's a heavy handed option if you are using jQuery:

_x000D_
_x000D_
var $selects = $('select');_x000D_
$selects.change(function () {_x000D_
  var option = $('option:default', this);_x000D_
  if(option && option.is(':selected')) {_x000D_
    $(this).css('color', '#999');_x000D_
  }_x000D_
  else {_x000D_
    $(this).css('color', '#555');_x000D_
  }_x000D_
});_x000D_
_x000D_
$selects.each(function() {_x000D_
  $(this).change();_x000D_
});
_x000D_
option {_x000D_
    color: #555;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<select name="in-op">_x000D_
    <option default selected>Select Option</option>_x000D_
    <option>Option 1</option>_x000D_
    <option>Option 2</option>_x000D_
    <option>Option 3</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


If you are using Angular, go like this:

_x000D_
_x000D_
<select>_x000D_
    <option [ngValue]="undefined"  disabled selected>Select your option</option>_x000D_
    <option [ngValue]="hurr">Durr</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


You could set the first option's color to gray, set it's display to none, set the select's color to gray, and add an input event listener to it that sets it's color to black.

_x000D_
_x000D_
select > option:not(:first-of-type) {
  color: black;
}
_x000D_
<select style='color:gray' oninput='style.color="black"'>
  <option style='display:none'>
    Choose an option
  </option>
  <option>
    1
  </option>
  <option>
    2
  </option>
  <option>
    3
  </option>
</select>
_x000D_
_x000D_
_x000D_

Using the customElement API:

_x000D_
_x000D_
class placeholderSelect extends HTMLElement {
  connectedCallback() {
    this.outerHTML = `<select style='color:gray' oninput='style.color="black"'>
  <option style='display:none'>
    ${this.getAttribute('data-placeholder')}
  </option>
  ${this.innerHTML}
</select>`

    Array.from(this.children).forEach(function(el, i) {
      if (i !== 0) {
        el.style.color = 'black'
      }
    })
  }
}

customElements.define('placeholder-select', placeholderSelect)
_x000D_
<placeholder-select data-placeholder='Choose an option'>
  <option>
    1
  </option>
  <option>
    2
  </option>
  <option>
    3
  </option>
</placeholder-select>
_x000D_
_x000D_
_x000D_


I'm not content with HTML/CSS-only solutions, so I've decided to create a custom select using JavaScript.

This is something I've written in the past 30 mins, thus it can be further improved.

All you have to do is create a simple list with few data attributes. The code automatically turns the list into a selectable dropdown. It also adds a hidden input to hold the selected value, so it can be used in a form.

Input:

<ul class="select" data-placeholder="Role" data-name="role">
  <li data-value="admin">Administrator</li>
  <li data-value="mod">Moderator</li>
  <li data-value="user">User</li>
</ul>

Output:

<div class="ul-select-container">
    <input type="hidden" name="role" class="hidden">
    <div class="selected placeholder">
        <span class="text">Role</span>
        <span class="icon">?</span>
    </div>
    <ul class="select" data-placeholder="Role" data-name="role">
        <li class="placeholder">Role</li>
        <li data-value="admin">Administrator</li>
        <li data-value="mod">Moderator</li>
        <li data-value="user">User</li>
    </ul>
</div>

The text of the item that's supposed to be a placeholder is grayed out. The placeholder is selectable, in case the user wants to revert his/her choice. Also using CSS, all the drawbacks of select can be overcome (e.g., inability of the styling of the options).

_x000D_
_x000D_
// Helper function to create elements faster/easier_x000D_
// https://github.com/akinuri/js-lib/blob/master/element.js_x000D_
var elem = function(tagName, attributes, children, isHTML) {_x000D_
  let parent;_x000D_
  if (typeof tagName == "string") {_x000D_
    parent = document.createElement(tagName);_x000D_
  } else if (tagName instanceof HTMLElement) {_x000D_
    parent = tagName;_x000D_
  }_x000D_
  if (attributes) {_x000D_
    for (let attribute in attributes) {_x000D_
      parent.setAttribute(attribute, attributes[attribute]);_x000D_
    }_x000D_
  }_x000D_
  var isHTML = isHTML || null;_x000D_
  if (children || children == 0) {_x000D_
    elem.append(parent, children, isHTML);_x000D_
  }_x000D_
  return parent;_x000D_
};_x000D_
elem.append = function(parent, children, isHTML) {_x000D_
  if (parent instanceof HTMLTextAreaElement || parent instanceof HTMLInputElement) {_x000D_
    if (children instanceof Text || typeof children == "string" || typeof children == "number") {_x000D_
      parent.value = children;_x000D_
    } else if (children instanceof Array) {_x000D_
      children.forEach(function(child) {_x000D_
        elem.append(parent, child);_x000D_
      });_x000D_
    } else if (typeof children == "function") {_x000D_
      elem.append(parent, children());_x000D_
    }_x000D_
  } else {_x000D_
    if (children instanceof HTMLElement || children instanceof Text) {_x000D_
      parent.appendChild(children);_x000D_
    } else if (typeof children == "string" || typeof children == "number") {_x000D_
      if (isHTML) {_x000D_
        parent.innerHTML += children;_x000D_
      } else {_x000D_
        parent.appendChild(document.createTextNode(children));_x000D_
      }_x000D_
    } else if (children instanceof Array) {_x000D_
      children.forEach(function(child) {_x000D_
        elem.append(parent, child);_x000D_
      });_x000D_
    } else if (typeof children == "function") {_x000D_
      elem.append(parent, children());_x000D_
    }_x000D_
  }_x000D_
};_x000D_
_x000D_
_x000D_
// Initialize all selects on the page_x000D_
$("ul.select").each(function() {_x000D_
  var parent    = this.parentElement;_x000D_
  var refElem   = this.nextElementSibling;_x000D_
  var container = elem("div", {"class": "ul-select-container"});_x000D_
  var hidden    = elem("input", {"type": "hidden", "name": this.dataset.name, "class": "hidden"});_x000D_
  var selected  = elem("div", {"class": "selected placeholder"}, [_x000D_
    elem("span", {"class": "text"}, this.dataset.placeholder),_x000D_
    elem("span", {"class": "icon"}, "&#9660;", true),_x000D_
  ]);_x000D_
  var placeholder = elem("li", {"class": "placeholder"}, this.dataset.placeholder);_x000D_
  this.insertBefore(placeholder, this.children[0]);_x000D_
  container.appendChild(hidden);_x000D_
  container.appendChild(selected);_x000D_
  container.appendChild(this);_x000D_
  parent.insertBefore(container, refElem);_x000D_
});_x000D_
_x000D_
// Update necessary elements with the selected option_x000D_
$(".ul-select-container ul li").on("click", function() {_x000D_
  var text     = this.innerText;_x000D_
  var value    = this.dataset.value || "";_x000D_
  var selected = this.parentElement.previousElementSibling;_x000D_
  var hidden   = selected.previousElementSibling;_x000D_
  hidden.value = selected.dataset.value = value;_x000D_
  selected.children[0].innerText = text;_x000D_
  if (this.classList.contains("placeholder")) {_x000D_
    selected.classList.add("placeholder");_x000D_
  } else {_x000D_
    selected.classList.remove("placeholder");_x000D_
  }_x000D_
  selected.parentElement.classList.remove("visible");_x000D_
});_x000D_
_x000D_
// Open select dropdown_x000D_
$(".ul-select-container .selected").on("click", function() {_x000D_
  if (this.parentElement.classList.contains("visible")) {_x000D_
    this.parentElement.classList.remove("visible");_x000D_
  } else {_x000D_
    this.parentElement.classList.add("visible");_x000D_
  }_x000D_
});_x000D_
_x000D_
// Close select when focus is lost_x000D_
$(document).on("click", function(e) {_x000D_
  var container = $(e.target).closest(".ul-select-container");_x000D_
  if (container.length == 0) {_x000D_
    $(".ul-select-container.visible").removeClass("visible");_x000D_
  }_x000D_
});
_x000D_
.ul-select-container {_x000D_
  width: 200px;_x000D_
  display: table;_x000D_
  position: relative;_x000D_
  margin: 1em 0;_x000D_
}_x000D_
.ul-select-container.visible ul {_x000D_
  display: block;_x000D_
  padding: 0;_x000D_
  list-style: none;_x000D_
  margin: 0;_x000D_
}_x000D_
.ul-select-container ul {_x000D_
  background-color: white;_x000D_
  border: 1px solid hsla(0, 0%, 60%);_x000D_
  border-top: none;_x000D_
  -webkit-user-select: none;_x000D_
  display: none;_x000D_
  position: absolute;_x000D_
  width: 100%;_x000D_
  z-index: 999;_x000D_
}_x000D_
.ul-select-container ul li {_x000D_
  padding: 2px 5px;_x000D_
}_x000D_
.ul-select-container ul li.placeholder {_x000D_
  opacity: 0.5;_x000D_
}_x000D_
.ul-select-container ul li:hover {_x000D_
  background-color: dodgerblue;_x000D_
  color: white;_x000D_
}_x000D_
.ul-select-container ul li.placeholder:hover {_x000D_
  background-color: rgba(0, 0, 0, .1);_x000D_
  color: initial;_x000D_
}_x000D_
.ul-select-container .selected {_x000D_
  background-color: white;_x000D_
  padding: 3px 10px 4px;_x000D_
  padding: 2px 5px;_x000D_
  border: 1px solid hsla(0, 0%, 60%);_x000D_
  -webkit-user-select: none;_x000D_
}_x000D_
.ul-select-container .selected {_x000D_
  display: flex;_x000D_
  justify-content: space-between;_x000D_
}_x000D_
.ul-select-container .selected.placeholder .text {_x000D_
  color: rgba(0, 0, 0, .5);_x000D_
}_x000D_
.ul-select-container .selected .icon {_x000D_
  font-size: .7em;_x000D_
  display: flex;_x000D_
  align-items: center;_x000D_
  opacity: 0.8;_x000D_
}_x000D_
.ul-select-container:hover .selected {_x000D_
  border: 1px solid hsla(0, 0%, 30%);_x000D_
}_x000D_
.ul-select-container:hover .selected .icon {_x000D_
  opacity: 1;_x000D_
}
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
_x000D_
<ul class="select" data-placeholder="Role" data-name="role">_x000D_
  <li data-value="admin">Administrator</li>_x000D_
  <li data-value="mod">Moderator</li>_x000D_
  <li data-value="user">User</li>_x000D_
</ul>_x000D_
_x000D_
<ul class="select" data-placeholder="Sex" data-name="sex">_x000D_
  <li data-value="male">Male</li>_x000D_
  <li data-value="female">Female</li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_


Update: I've improved this (selection using up/down/enter keys), tidied up the output a little bit, and turned this into a object. Current output:

<div class="li-select-container">
    <input type="text" readonly="" placeholder="Role" title="Role">
    <span class="arrow">?</span>
    <ul class="select">
        <li class="placeholder">Role</li>
        <li data-value="admin">Administrator</li>
        <li data-value="mod">Moderator</li>
        <li data-value="user">User</li>
    </ul>
</div>

Initialization:

new Liselect(document.getElementsByTagName("ul")[0]);

For further examination: JSFiddle, GitHub (renamed).


Update: I am have rewritten this again. Instead of using a list, we can just use a select. This way it'll work even without JavaScript (in case it's disabled).

Input:

<select name="role" data-placeholder="Role" required title="Role">
    <option value="admin">Administrator</option>
    <option value="mod">Moderator</option>
    <option>User</option>
</select>

new Advancelect(document.getElementsByTagName("select")[0]);

Output:

<div class="advanced-select">
    <input type="text" readonly="" placeholder="Role" title="Role" required="" name="role">
    <span class="arrow">?</span>
    <ul>
        <li class="placeholder">Role</li>
        <li data-value="admin">Administrator</li>
        <li data-value="mod">Moderator</li>
        <li>User</li>
    </ul>
</div>

JSFiddle, GitHub.


In Angular we can add an option as placeholder that can be hidden in option dropdown. We can even add a custom dropdown icon as background that replaces browser dropdown icon.

The trick is to enable placeholder css only when value is not selected

/**My Component Template*/

 <div class="dropdown">
      <select [ngClass]="{'placeholder': !myForm.value.myField}"
 class="form-control" formControlName="myField">
        <option value="" hidden >Select a Gender</option>
        <option value="Male">Male</option>
        <option value="Female">Female</option>
      </select>
    </div>

/**My Component.TS */

constructor(fb: FormBuilder) {
  this.myForm = this.fb.build({
    myField: ''
  });
}

/**global.scss*/

.dropdown {
  width: 100%;
  height: 30px;
  overflow: hidden;
  background: no-repeat white;
  background-image:url('angle-arrow-down.svg');
  background-position: center right;
  select {
    background: transparent;
    padding: 3px;
    font-size: 1.2em;
    height: 30px;
    width: 100%;
    overflow: hidden;

    /*For moz*/
    -moz-appearance: none;
    /* IE10 */
    &::-ms-expand {
      display: none;
    }
    /*For chrome*/
    -webkit-appearance:none;
    &.placeholder {
      opacity: 0.7;
      color: theme-color('mutedColor');
    }
    option {
      color: black;
    }
  }
}

If you're reading this and using React, use defaultValue.

<option defaultValue>Select a country here</option>

Another possibility in JavaScript:

 $('body').on('change', 'select', function (ev){
    if($(this).find('option:selected').val() == ""){
        $(this).css('color', '#999');
        $(this).children().css('color', 'black');
    }
    else {
        $(this).css('color', 'black');
        $(this).children().css('color', 'black');
    }
});

JSFiddle


The solution below works in Firefox also, without any JavaScript:

_x000D_
_x000D_
option[default] {_x000D_
  display: none;_x000D_
}
_x000D_
<select>_x000D_
  <option value="" default selected>Select Your Age</option>_x000D_
  <option value="1">1</option>_x000D_
  <option value="2">2</option>_x000D_
  <option value="3">3</option>_x000D_
  <option value="4">4</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


Here is a working example how to achieve this with pure JavaScript that handles the options color after the first click:

<!DOCTYPE html>
<html>
  <head>
    <style>
      #myselect {
        color: gray;
      }
    </style>
  </head>

  <body>
    <select id="myselect">
      <option disabled selected>Choose Item
      </option>

      <option>Item 1
      </option>

      <option>Item 2
      </option>

      <option>Item 3
      </option>
    </select>

    <script>
      // Add event listener to change color in the first click
      document.getElementById("myselect").addEventListener("click", setColor)
      function setColor()
      {
        var combo = document.getElementById("myselect");
        combo.style.color = 'red';
        // Remove Event Listener after the color is changed at the first click
        combo.removeEventListener("click", setColor);
      }
    </script>
  </body>
</html>

I see signs of correct answers, but to bring it all together, this would be my solution:

_x000D_
_x000D_
select {_x000D_
  color: grey;_x000D_
}_x000D_
_x000D_
option {_x000D_
  color: black;_x000D_
}_x000D_
_x000D_
option[default] {_x000D_
   display: none;_x000D_
}
_x000D_
<select>_x000D_
    <option value="" default selected>Select your option</option>_x000D_
    <option value="hurr">Durr</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


Here's my contribution. Haml + CoffeeScript + SCSS

Haml

=f.collection_select :country_id, [us] + Country.all, :id, :name, {prompt: t('user.country')}, class: 'form-control'

CoffeeScript

  $('select').on 'change', ->
    if $(this).val()
      $(this).css('color', 'black')
    else
      $(this).css('color', 'gray')
  $('select').change()

SCSS

select option {
  color: black;
}

It's possible to use only CSS by changing the server code and only setting the class styles depending on the current value of the property, but this way seems easier and cleaner.

_x000D_
_x000D_
$('select').on('change', function() {_x000D_
  if ($(this).val()) {_x000D_
    return $(this).css('color', 'black');_x000D_
  } else {_x000D_
    return $(this).css('color', 'gray');_x000D_
  }_x000D_
});_x000D_
_x000D_
$('select').change();
_x000D_
    select option {_x000D_
      color: black;_x000D_
    }
_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<select class="form-control" name="user[country_id]" id="user_country_id">_x000D_
  <option value="">Country</option>_x000D_
                      <option value="231">United States</option>_x000D_
                      <option value="1">Andorra</option>_x000D_
                      <option value="2">Afghanistan</option>_x000D_
                      <option value="248">Zimbabwe</option></select>
_x000D_
_x000D_
_x000D_

You can add more CSS (select option:first-child) to keep the placeholder gray when it opens, but I didn't care about that.


For a required field, there is a pure-CSS solution in modern browsers:

_x000D_
_x000D_
select:required:invalid {_x000D_
  color: gray;_x000D_
}_x000D_
option[value=""][disabled] {_x000D_
  display: none;_x000D_
}_x000D_
option {_x000D_
  color: black;_x000D_
}
_x000D_
<select required>_x000D_
  <option value="" disabled selected>Select something...</option>_x000D_
  <option value="1">One</option>_x000D_
  <option value="2">Two</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


Here I have modified David's answer (accepted answer). On his answer, he put disabled and selected attribute on the option tag, but when we also put hidden tag then it will look much better.

By adding an extra hidden attribute on the option tag, it will prevent the "Select your option" option from being re-selecting after the "Durr" option is selected.

_x000D_
_x000D_
<select>_x000D_
    <option value="" disabled selected hidden>Select your option</option>_x000D_
    <option value="hurr">Durr</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


Something like this:

HTML:

<select id="choice">
    <option value="0" selected="selected">Choose...</option>
    <option value="1">Something</option>
    <option value="2">Something else</option>
    <option value="3">Another choice</option>
</select>

CSS:

#choice option { color: black; }
.empty { color: gray; }

JavaScript:

$("#choice").change(function () {
    if($(this).val() == "0") $(this).addClass("empty");
    else $(this).removeClass("empty")
});

$("#choice").change();

Working example: http://jsfiddle.net/Zmf6t/


try this it work good for my

<select class="form-control">
    <option value="" readonly="true" hidden="true" selected>Select your option</option>
    <option value="1">Something</option>
    <option value="2">Something else</option>
    <option value="3">Another choice</option>
</select>

Based on Albireo's response, this version uses no jQuery and the CSS specificity is better.

_x000D_
_x000D_
const triggerEvent = (el, eventName) => {_x000D_
  let event = document.createEvent('HTMLEvents')_x000D_
  event.initEvent(eventName, true, false)_x000D_
  el.dispatchEvent(event)_x000D_
}_x000D_
_x000D_
let select = document.querySelector('.placeholder-select')_x000D_
select.addEventListener('change', (e) => {_x000D_
  e.target.classList[e.target.value == 0 ? 'add' : 'remove']('empty')_x000D_
})_x000D_
triggerEvent(select, 'change')
_x000D_
.placeholder-select option {_x000D_
  color: #000000;_x000D_
}_x000D_
.placeholder-select option:first-child {_x000D_
  color: #444444;_x000D_
  font-style: italic;_x000D_
  font-weight: bold;_x000D_
}_x000D_
.placeholder-select.empty {_x000D_
  color: #7F7F7F;_x000D_
}
_x000D_
<select class="placeholder-select">_x000D_
  <option value="0" selected="selected">Choose...</option>_x000D_
  <option value="1">Something</option>_x000D_
  <option value="2">Something else</option>_x000D_
  <option value="3">Another choice</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


Try this for a change:

$("select").css("color", "#757575");
$(document).on("change", "select", function(){
    if ($(this).val() != "") {
        $(this).css("color", "");
    } 
    else {
        $(this).css("color", "#757575");
    }
});

This HTML + CSS solution worked for me:

_x000D_
_x000D_
form select:invalid {_x000D_
  color: gray;_x000D_
}_x000D_
_x000D_
form select option:first-child {_x000D_
  color: gray;_x000D_
}_x000D_
_x000D_
form select:invalid option:not(:first-child) {_x000D_
  color: black;_x000D_
}
_x000D_
<form>_x000D_
  <select required>_x000D_
    <option value="">Select Planet...</option>_x000D_
    <option value="earth">Earth</option>_x000D_
    <option value="pandora">Pandora</option>_x000D_
  </select>_x000D_
</form>
_x000D_
_x000D_
_x000D_

Good Luck...


I had the same problem and while searching I came across this question, and after I found a good solution for me, I would like to share it with you guys in case some one can benefit from it.

Here it is:

HTML:

<select class="place_holder dropdown">
    <option selected="selected" style=" display: none;">Sort by</option>
    <option>two</option>
    <option>something</option>
    <option>4</option>
    <option>5</option>
</select>

CSS:

.place_holder {
    color: gray;
}
option {
    color: #000000;
}

JavaScript:

jQuery(".dropdown").change(function () {
    jQuery(this).removeClass("place_holder");
});

After the customer makes the first select, there isn't any need for gray color, so the JavaScript code removes the class place_holder.

Thanks to @user1096901, as a workaround for the Internet Explorer browser, you can add the place_holder class again in case the first option is selected again :)


I wanted the SELECT to be grey until selected so for this piece of HTML:

<select>
  <option value="" disabled selected>Select your option</option>
  <option value="hurr">Durr</option>
</select>

I've added these CSS definitions:

select { color: grey; }
select:valid { color: black; }

It works as expected in Chrome / Safari and maybe also in other browsers, but I haven't checked.


The user should not see the placeholder in select options. I suggest to use the hidden attribute for the placeholder option, and you don't need the selected attribute for this option. You can just put it as the first.

_x000D_
_x000D_
select:not(:valid) {_x000D_
  color: #999;_x000D_
}
_x000D_
<select required>_x000D_
    <option value="" hidden>Select your option</option>_x000D_
    <option value="0">First option</option>_x000D_
    <option value="1">Second option</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to html-select

How can I get new selection in "select" in Angular 2? How to show disable HTML select option in by default? Remove Select arrow on IE Bootstrap 3 select input form inline Change <select>'s option and trigger events with JavaScript How to use a Bootstrap 3 glyphicon in an html select Creating a select box with a search option Drop Down Menu/Text Field in one How to have a default option in Angular.js select box How to set the 'selected option' of a select dropdown list with jquery

Examples related to placeholder

Keep placeholder text in UITextField on input in IOS HTML Input - already filled in text Add placeholder text inside UITextView in Swift? Bootstrap select dropdown list placeholder fail to change placeholder color with Bootstrap 3 Not showing placeholder for input type="date" field Use Font Awesome Icon in Placeholder How do I put hint in a asp:textbox How to support placeholder attribute in IE8 and 9 HTML5 image icon to input placeholder