3

I'm aiming to do a select element that has an icon next to it, like below. If the user clicks anywhere inside the "button" (including the icon), the option list should be displayed.

enter image description here

function Select() {
  return (
    <div>
      <select>
        <option value="">Choose an option</option>
        <option value="dog">Dog</option>
        <option value="cat">Cat</option>
        <option value="hamster">Hamster</option>
      </select>
      <ImportedSvg />
    </div>
  )
}

I know there is a CSS way to solve this by having the image as a background to the select tag. As well as creating a custom option list.

However, I want the browser default option list and I need to use a React element for the image. And lastly, I don't want a library dependency to solve this (e.g. FontAwesome or Material UI).

Is there any way to accomplish the above?

Fellow Stranger
  • 32,129
  • 35
  • 168
  • 232

4 Answers4

1

<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" integrity="sha256-+N4/V/SbAFiW1MPBCXnfnP9QSN3+Keu+NlB+0ev/YKQ=" crossorigin="anonymous" />
</head>
<style>
.dropbtn {
  background-color: white;    
  color: #525252;
  padding: 16px;
  font-size: 16px;
  border: solid 1px black;
  cursor: pointer;
}

.dropbtn:hover, .dropbtn:focus {
}

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: white;
  min-width: 160px;
  overflow: auto;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  z-index: 1;
}

.dropdown-content a {
  color: black;
  padding: 12px 16px;
  text-decoration: none;
  display: block;
}

.dropdown a:hover {background-color: #ddd;}

.show {display: block;}
</style>
<body>


<div class="dropdown">
  <button onclick="myFunction()" class="dropbtn">Choose an option <i class="fas fa-caret-down"></i></button>
  <div id="myDropdown" class="dropdown-content">
    <a href="#">Dog</a>
    <a href="#">Cat</a>
    <a href="#">Hamster</a>
  </div>
</div>

<script>
function myFunction() {
  document.getElementById("myDropdown").classList.toggle("show");
}

// Close the dropdown if the user clicks outside of it
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {
    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}
</script>
0

You probably can use label instead of img. When click on label dropdown can be shown:

return (
  <div>
    <select id={ id }>
      ...
    </select>
    <label htmlFor={ id } />
  </div>
);
Andres
  • 967
  • 6
  • 7
0

I finally solved it with a ridiculously simple approach - by absolute-positioning the image inside the select while giving the select transparent background.

Complete code (with styled-components):

const Wrapper = styled.div({
  alignItems: 'center',
  display: 'inline-flex',
  background: '#fff',
  position: 'relative',
})
const StyledSelect = styled.select({
  appearance: 'none',
  border: '1px solid #ccc',
  borderRadius: 4,
  height: 40,
  paddingRight: 30,
  zIndex: 20,
  paddingLeft: 12,
  background: 'transparent',
})
const StyledImageComponent = styled(ImageComponent)({
  position: 'absolute',
  zIndex: 10,
  right: 12,
})

export function Select({ options, onChange, currentValue }) {
  return (
    <Wrapper>
      <StyledSelect onChange={onChange} defaultValue={currentValue}>
        {options.map(({ value, label }) => (
          <option key={value} value={value}>
            {label}
          </option>
        ))}
      </StyledSelect>
      <StyledImageComponent />
    </Wrapper>
  )
}
Fellow Stranger
  • 32,129
  • 35
  • 168
  • 232
0

If you use icon font like font-awesome or google material icons you can do this with pure css.

Use ::before or ::after to control the icon, and use properties content or background to render desired icon.

  <div class="select">
    <select name="dropdown" id="dropdown">
      <option>11</option>
      <option>12</option>
      <option>13</option>
      <option>14</option>
    </select>
  </div>
.select {
  display: inline-block;
  position: relative;
  width: 100%;
  max-width: 150px;
  background: white;
}

.select::before {
  display: block;
  content: '';
  /*If you use font icon, put icon reference here*/
  background: black;
  /* If you use background image, place it here*/
  width: 20px;
  height: 20px;
  position: absolute;
  top: calc(50% - 10px);
  right: 5px;
  pointer-events: none;
}

select {
  width: 100%;
  border: 1px solid #eeeeee;
  padding: 5px 20px 5px 5px;
}


/* Remove default dropdown indicator */

select {
  /* for Firefox */
  -moz-appearance: none;
  /* for Chrome */
  -webkit-appearance: none;
}


/* For IE10 */

select::-ms-expand {
  display: none;
}

https://plnkr.co/edit/pjjwTEGOiSPZj1MkUgRW

Mike N.
  • 51
  • 5