Reputation: 3950
Is it possible to change the default background color of a select list option on hover?
option:hover {
background-color: red;
}
<select id="select">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
I have tried option:hover { background-color: red; }
, but it is of no use. Does anybody know how to do this?
Upvotes: 110
Views: 432234
Reputation: 541
This way we can do this with minimal changes :)
option:hover {
background-color: yellow;
}
<select onfocus='this.size=10;' onblur='this.size=0;' onchange='this.size=1; this.blur();'>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
Note: This solution requires JavaScript to work
Upvotes: 28
Reputation: 17225
Adding/toggling size
attributes on focus event as suggestest by @Krishnaraj works pretty well on desktop using mouse controls.
However, the previous answers don't work well with keyboard controls.
The following example wraps the aforementioned state toggling into a javaScript helper function and adds additional event listeners for better accessibility
setSelectHover();
function setSelectHover(selector = "select") {
let selects = document.querySelectorAll(selector);
selects.forEach((select) => {
let selectWrap = select.parentNode.closest(".select-wrap");
// wrap select element if not previously wrapped
if (!selectWrap) {
selectWrap = document.createElement("div");
selectWrap.classList.add("select-wrap");
select.parentNode.insertBefore(selectWrap, select);
selectWrap.appendChild(select);
}
// set expanded height according to options
let size = select.querySelectorAll("option").length;
// adjust height on resize
const getSelectHeight = () => {
selectWrap.style.height = "auto";
let selectHeight = select.getBoundingClientRect();
selectWrap.style.height = selectHeight.height + "px";
};
getSelectHeight(select);
window.addEventListener("resize", (e) => {
getSelectHeight(select);
});
/**
* focus and click events will coincide
* adding a delay via setTimeout() enables the handling of
* clicks events after the select is focused
*/
let hasFocus = false;
select.addEventListener("focus", (e) => {
select.setAttribute("size", size);
setTimeout(() => {
hasFocus = true;
}, 150);
});
// close select if already expanded via focus event
select.addEventListener("click", (e) => {
if (hasFocus) {
select.blur();
hasFocus = false;
}
});
// close select if selection was set via keyboard controls
select.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
select.removeAttribute("size");
select.blur();
}
});
// collapse select
select.addEventListener("blur", (e) => {
select.removeAttribute("size");
hasFocus = false;
});
});
}
body {
font-size: 10vmin;
}
select {
--selectHoverCol: #999;
--selectedCol: red;
width: 100%;
font-size: 1em;
padding: 0.3em;
background-color: #fff;
}
select:focus {
border-radius: 0px;
border-color: red;
background: #fff;
outline: none;
}
.select-wrap {
position: relative;
}
.select-wrap:focus-within select {
position: absolute;
top: 0;
left: 0;
z-index: 10
}
option:hover {
background-color: var(--selectHoverCol);
color: #fff;
}
option:checked {
box-shadow: 0 0 1em 100px var(--selectedCol) inset;
}
<select class="selectHovercolor">
<option value="volvo" selected>Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
<p>paragraph</p>
<select>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
<option value="Lexus">Lexus</option>
<option value="Mercedes">Mercedes</option>
</select>
<p>paragraph</p>
<div>
with relative position.:focus-within
pseudo state toggles the select positioning between absolute and initial (static) – this way we can avoid layout shifts.size
attribute is set according to the actual number of <option>
elementsUpvotes: 2
Reputation: 882
I would consider switching from a <select>
element to a <div>
list, like below:
https://jsfiddle.net/getbutterfly/gquh02dz/
This will make it cross-browser compatible. Every other method using CSS appearance
tricks and <select>
dropdowns is hacky.
HTML
<div class="sel">
<div class="label">Select option...</div>
<div class="options">
<div>Option 1</div>
<div>Option 2</div>
<div>Option 3</div>
<div>Lot of text to display, so it can expand multiple lines and expand the select main text also</div>
</div>
</div>
JavaScript
const sel = document.querySelector('.sel');
const label = document.querySelector('.label');
const options = document.querySelector('.options');
options.setAttribute('hidden', true);
sel.addEventListener('click', (e) => {
e.stopPropagation();
options.removeAttribute('hidden');
});
document.body.addEventListener('click', (e) => {
options.setAttribute('hidden', true);
});
options.addEventListener('click', (e) => {
if (e.target.tagName === 'DIV') {
e.stopPropagation();
label.textContent = e.target.textContent;
e.target.classList.add('selected');
Array.from(e.target.parentNode.children).forEach((child) => {
if (child !== e.target) {
child.classList.remove('selected');
}
});
options.setAttribute('hidden', true);
}
});
CSS
* {
box-sizing: border-box;
}
.sel {
color: #000000;
width: 250px;
box-sizing: border-box;
background-color: #ffffff;
border: 1px solid #000000;
overflow: hidden;
background: url("data:image/svg+xml,<svg height='10px' width='10px' viewBox='0 0 16 16' fill='%23000000' xmlns='http://www.w3.org/2000/svg'><path d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/></svg>") no-repeat calc(100% - 10px) 14px;
}
.label,
.sel .options div {
padding: 10px;
}
.selected {
background-color: #ff0000;
}
.sel .options {
width: 250px;
background-color: #ffffff;
}
.sel .options div:hover {
background-color: #00ff00;
}
With a bit of extra CSS, the dropdown can be animated and the selected text can be truncated to fit inside a fixed height, behaving exactly like a <select>
element.
Upvotes: 2
Reputation: 1120
This worked for me in chrome!
<select onfocus='this.size=10;'>
<option>Crossing</option>
<option>Crossing Up</option>
<option>Crossing Down</option>
</select>
<style>
select option:hover {
box-shadow: 0 0 10px 100px green inset;
color:white;
}
select option:checked{
box-shadow: 0 0 10px 100px green inset;
}
</style>
However, the checked option's background will remain same even if i hover on another option
By the way, you can do that one as well. Here is the link for that: https://www.w3schools.com/howto/howto_custom_select.asp
Upvotes: 0
Reputation: 207
Select / Option elements are rendered by the OS/Client, not HTML. You cannot change the style for these elements in modern Browser.
On older clients
select option:checked,
select option:hover {
box-shadow: 0 0 10px 100px #000 inset;
}
Checked option item works in older Chrome:
select:focus > option:checked {
background: #000 !important;
}
Upvotes: 2
Reputation: 11
<html>
<head>
<style>
option:hover {
background-color: yellow;
}
</style>
</head>
<body>
<select onfocus='this.size=10;' onblur='this.size=0;' onchange='this.size=1; this.blur();'>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
</body>
</html>
Upvotes: 0
Reputation: 411
You can do this, just know that it will change all of the select inputs throughout the html, it doesn't change the blue hover, but it does style everything else.
option {
background: #1b1a1a !important;
color: #357b1d !important;
}
select {
background: #1b1a1a !important;
color: #357b1d !important;
}
// If you also want to theme your text inputs:
input {
background: #1b1a1a !important;
color: #357b1d !important;
}
Upvotes: 0
Reputation: 13729
The problem is that even JavaScript does not see the option
element being hovered. This is just to put emphasis on how it's not going to be solved (any time soon at least) by using just CSS:
window.onmouseover = function(event)
{
console.log(event.target.nodeName);
}
The only way to resolve this issue (besides waiting a millennia for browser vendors to fix bugs, let alone one that afflicts what you're trying to do) is to replace the drop-down menu with your own HTML/XML using JavaScript. This would likely involve the use of replacing the select
element with a ul
element and the use of a radio
input
element per li
element.
Upvotes: 9
Reputation: 332
Implementing an inset box shadow CSS works on Firefox:
select option:checked,
select option:hover {
box-shadow: 0 0 10px 100px #000 inset;
}
Checked option item works in Chrome:
select:focus > option:checked {
background: #000 !important;
}
There is test on https://codepen.io/egle/pen/zzOKLe
For me this is working on Google Chrome Version 76.0.3809.100 (Official Build) (64-bit)
Newest article I have found about this issue by Chris Coyier (Oct 28, 2019) https://css-tricks.com/the-current-state-of-styling-selects-in-2019/
Upvotes: 12
Reputation: 511
This can be done by implementing an inset box shadow. eg:
select.decorated option:hover {
box-shadow: 0 0 10px 100px #1882A8 inset;
}
Here, .decorated
is a class assigned to the select box.
Hope you got the point.
Upvotes: 47
Reputation: 51
I realise this is an older question, but I recently came across this need and came up with the following solution using jQuery and CSS:
jQuery('select[name*="lstDestinations"] option').hover(
function() {
jQuery(this).addClass('highlight');
}, function() {
jQuery(this).removeClass('highlight');
}
);
and the css:
.highlight {
background-color:#333;
cursor:pointer;
}
Perhaps this helps someone else.
Upvotes: -5
Reputation: 9
this is what you need, the child combinator:
select>option:hover
{
color: #1B517E;
cursor: pointer;
}
Try it, works perfect.
Here's the reference: http://www.w3schools.com/css/css_combinators.asp
Upvotes: -10
Reputation: 429
Select / Option elements are rendered by the OS, not HTML. You cannot change the style for these elements.
Upvotes: 31