Home > Mobile >  How do I highlight proper border boxes applying focus on stacked input fields?
How do I highlight proper border boxes applying focus on stacked input fields?

Time:01-21

I have an application with "stacked" input fields like so:

enter image description here

As you can see from the image, when a field is receiving focus, I only want the borders of that particular input element to be highlighted. I also want to avoid a particularly thick border by having both a top and bottom border that corresponds to the same middle lines.

Here is a Fiddle: https://jsfiddle.net/3nL426uy/

Creating the stacked input fields and applying borders is not a problem. I simply remove the bottom border on all the input fields and on the last field, I apply a bottom border.

The issue comes in when I want to apply the focus styles. As it stands currently, simply applying a different border color (used red in the example to clearly show the contrast) results in a red bottom border and a gray top border of the input field below it. Now, I may be able to use an Id selector on that particular field and apply a full border, however, how do I remove the top border of the input field below it?

const inputWrappers = document.querySelectorAll(".input-wrapper")

const wrappers = [...inputWrappers]

wrappers.forEach(wrapper => {
  wrapper.addEventListener('focusin', (event) => {
    event.target.classList.add('selected');     
  });
  
  wrapper.addEventListener('focusout', (event) => {
    event.target.classList.remove('selected');
  });
})
.wrapper {
  display: flex;
  flex-direction: column;
}

.item {
  width: 300px;
  height: 30px;
  padding: 5px 15px;
  border: 1px solid gray;
  border-radius: 0;
  border-bottom: 0;
}

/* Remove the default input focus-visible outline */
.item:focus-visible {
  outline: 0;
}

.input-wrapper:last-child .item {
  border-bottom: 1px solid gray;
}

.selected {
  border: 1px solid red;
}
<div >
  <div  >
    <input  placeholder="Enter item..." />
  </div>
  <div >
    <input  placeholder="Enter item..." />
  </div>
  <div >
    <input  placeholder="Enter item..." />
  </div>
  <div >
    <input  placeholder="Enter item..." />
  </div>
</div>

CodePudding user response:

I'm not sure why you've used any JavaScript here? You can just set a new focus style in the :focus-visible CSS rule, you don't need to add and remove a class when the inputs receive and lose keyboard focus.

To collapse the margins, I'd recommend applying margin-top: -1px; to each of the siblings with borders. Then, to make sure the current one has its borders on top, you can give it a z-index above its siblings. I've also added a couple of lines here to ensure that z-index won't escape the .wrapper element by creating its own stacking context.

.wrapper {
  display: flex;
  flex-direction: column;
  /* Create a new stacking context to contain z-index */
  isolation: isolate;
  transform: scale(1);
}

.item {
  width: 300px;
  height: 30px;
  padding: 5px 15px;
  border: 1px solid gray;
  border-radius: 0;
}


/* Remove the default input focus-visible outline */

.item:focus-visible {
  outline: 0;
  border-color: red;
  /* Setting a z-index on the focused element ensures its borders are on top */
  position: relative;
  z-index: 1;
}

.input-wrapper {
  /* A negative top margin lets the borders collapse */
  margin-top: -1px;
}

.container {
  /* Offset the negative top margin of the items */
  margin-top: 1px;
}
<div >
  <div >
    <input  placeholder="Enter item..." />
  </div>
  <div >
    <input  placeholder="Enter item..." />
  </div>
  <div >
    <input  placeholder="Enter item..." />
  </div>
  <div >
    <input  placeholder="Enter item..." />
  </div>
</div>

CodePudding user response:

you can add 'selected' class to the div element;

wrappers.forEach(wrapper => {
  wrapper.addEventListener('focusin', (event) => {
    event.target.parentNode.classList.add('selected');      
  });
  
  wrapper.addEventListener('focusout', (event) => {
    event.target.parentNode.classList.remove('selected');
  });
})

and then use sibling selector x y to select below div, remove the top boarder.

.selected .item{
  border: 1px solid red;
}

/* remove below div top border */
.selected .input-wrapper .item{
  border-top: 0;
}

.input-wrapper:last-child.selected .item{
  border-bottom: 1px solid red;
}

here is the whole example https://jsfiddle.net/2tuzi/koqrcxaw/

  •  Tags:  
  • Related