Custom CSS dropdown to focus on dropdown elements

Viewed 1707

I am trying to get the dropdown elements to focus while the list is in open state using CSS. Right now, the autofocus only selects the All, then closes the list dropdown. I want it to focus on cheese in an open state and focus tab through Toast and any components that could be after. I have tried placing tabIndex on each element, but the list dropdown closes so I don't see the focus.

Please, see CodeSandBox here.

.select-box {
  position: relative;
  display: block;
  width: 100%;
  height: 48px;
  margin: 0 auto;
}

.select-box-current:hover {
  border: 1px solid #D4D4D4;
}

.select-box-current:focus {
  box-shadow: 0 0 4px 2px #8CB6FD, 0 1px 3px 0 rgba(102, 102, 102, 0.1), 0 1px 3px 0 rgba(102, 102, 102, 0.2);
}

.select-box-current {
  position: relative;
  cursor: pointer;
  outline: none;
}

.select-box-current:focus+.select-box-list {
  opacity: 1;
  animation-name: none;
}

.select-box-current:focus+.select-box-list .select-box-option {
  cursor: pointer;
}

.select-box-value {
  display: flex;
}

.select-box-input {
  display: none;
}

.select-box-input:checked+.select-box-input-text {
  display: block;
}

.select-box-input-text {
  display: none;
  width: 100%;
  margin: 0;
  padding: 15px;
  background-color: #fff;
}

.select-box-list {
  position: absolute;
  width: 100%;
  padding: 0;
  margin-top: 8px;
  margin-bottom: 8px;
  list-style: none;
  opacity: 0;
  animation-name: HideList;
  animation-duration: 0.5s;
  animation-delay: 0.5s;
  animation-fill-mode: forwards;
  animation-timing-function: step-start;
  background-color: #FFFFFF;
}

.select-box-option {
  display: block;
  padding: 15px;
  background-color: #fff;
}

.select-box-option:hover {
  background-color: rgba(102, 102, 102, 0.05);
}

.select-box-option:focus {
  background-color: rgba(102, 102, 102, 0.05);
  box-shadow: 0 0 4px 2px #8CB6FD;
}

@keyframes HideList {
  from {
    transform: scaleY(1);
  }
  to {
    transform: scaleY(0);
  }
}
<div className="select-box">
  <div className="select-box-current" tabIndex="0" autoFocus={true}>
    <div className="select-box-value">
      <input className="select-box-input" type="radio" id={0} value="all" name="Ben" defaultChecked />
      <p className="select-box-input-text">
        All
      </p>
    </div>

    <div key={idx} className="select-box-value">
      <input className="select-box-input" type="radio" id={1} value="Cheese" name="Ben" />
      <p className="select-box-input-text">
        Cheese
      </p>
    </div>

    <div className="select-box-value">
      <input className="select-box-input" type="radio" id={2} value="Toast" name="Ben" />
      <p className="select-box-input-text">
        Toast
      </p>
    </div>

  </div>
  <ul className="select-box-list">
    <li>
      <label className="select-box-option" htmlFor={0} aria-hidden={false}>
                            All
                        </label>
    </li>

    <li>
      <label className="select-box-option" htmlFor={1} aria-hidden={false}>
                                Cheese
                            </label>
    </li>

    <li>
      <label className="select-box-option" htmlFor={2} aria-hidden={false}>
                                Toast
                            </label>
    </li>
  </ul>
</div>

2 Answers

If you want to use a little you can easily do this by just switch its class back and forth.

<script>
  document.getElementById("something").classList.toggle(".open")
</script>

I don't think you should force this pure CSS focus implementation. The reason is: you can only have 1 element focused. That is why the dropdown closes when 1 of the dropdown items is focused on.

I recommend to solve this by switching from psuedo class :focus to class active for the dropdown items

.select-box-option.active {
  background-color: rgba(102, 102, 102, 0.05);
  box-shadow: 0 0 4px 2px #8cb6fd;
}

Track the active item via state that updates when a different input is selected

const [activeItem, setActiveItem] = React.useState("cheese");

<input
  className="select-box-input"
  type="radio"
  id={1}
  value="toast"
  name="Ben"
  onChange={() => setActiveItem("toast")}
/>

And as mentioned by the others, you can use arrow navigation for the User Experience, because again, using tab will cause issues because it will change focus and close your dropdown.

window.addEventListener("keydown", handleKeydown);

function handleKeydown(e) {
  if (e.keyCode === 40) {
    // down arrow key
  } else if (e.keyCode === 38) {
    // up arrow key
  }
}

Edit htmlFor

Related