Ryan Peschel
Ryan Peschel

Reputation: 11756

How to prevent an absolutely positioned popover from clipping out of its container?

function myclick() {
  let node = document.createElement("div");
  node.className = "popover";
  node.innerText = "hello world hello world";
  event.srcElement.appendChild(node);
}
.container {
  width: 230px;
  height: 200px;
  border: 1px solid #ddd;
  display: flex;
  flex-flow: wrap;
}

.tag {
  border: 1px solid #ddd;
  padding: 5px;
  margin: 5px;
  display: flex;
  height: 20px;
  position: relative;
}

.popover {
  position: absolute;
  top: 30px;
  width: 60px;
  left: 0px;
  background-color: #dfdfdf;
}
<div class="container">
  <div class="tag" onclick="myclick();">apple</div>
  <div class="tag" onclick="myclick();">banana</div>
  <div class="tag" onclick="myclick();">carrot</div>
  <div class="tag" onclick="myclick();">dog</div>
  <div class="tag" onclick="myclick();">elephant</div>
  <div class="tag" onclick="myclick();">firetruck</div>
</div>

I've developed a complete reproduction of the issue I'm facing above. Basically, I have popovers appear from tags when you click on them. This all works perfectly, except for when the tag is near the edge of its container. In this case the tag clips out of the container. In the provided example if you click "dog" then the popover clips outside of the container div.

Rather, I would like the popover to move to the left as much as necessary in order to prevent itself from clipping out of the container. I've been messing with it for a while but I cannot quite figure out how to accomplish this.

Upvotes: 3

Views: 1020

Answers (3)

zgood
zgood

Reputation: 12581

You can try this. I added a javascript function called onEdge that is suppose to detect how close a child element is to the edge. This will probably need modified for your needs (like setting how close to the parents edge you consider "too close").

function onEdge(child) {
  if (child.parentElement.offsetWidth < (child.offsetLeft + child.offsetWidth))
    return true;
  return false;
}

function myclick(elm) {
  var addClass = onEdge(elm);

  let node = document.createElement("div");
  node.className = "popover" + (addClass ? " right" : "");
  node.innerText = "hello world hello world";
  event.srcElement.appendChild(node);
}
.container {
  width: 230px;
  height: 200px;
  border: 1px solid #ddd;
  display: flex;
  flex-flow: wrap;
}

.tag {
  border: 1px solid #ddd;
  padding: 5px;
  margin: 5px;
  display: flex;
  height: 20px;
  position: relative;
}

.popover {
  position: absolute;
  top: 30px;
  width: 60px;
  left: 0px;
  background-color: #dfdfdf;
}

.popover.right {
  left: auto;
  right: 0;
}
<div id="tag-container" class="container">
  <div class="tag" onclick="myclick(this);">apple</div>
  <div class="tag" onclick="myclick(this);">banana</div>
  <div class="tag" onclick="myclick(this);">carrot</div>
  <div class="tag" onclick="myclick(this);">dog</div>
  <div class="tag" onclick="myclick(this);">elephant</div>
  <div class="tag" onclick="myclick(this);">firetruck</div>
</div>

Upvotes: 2

Bingostew
Bingostew

Reputation: 138

EDITED: You can calculate the right point of the tag and check if the popup has enough room. Add a parameter to myclick and pass in the element.

var popUpWidth = 60;
var containerWidth = 200;
function myclick(element) {
  let node = document.createElement("div");

  if(element.offsetLeft + popUpWidth > containerWidth){
     node.style.left = -20 + "px";
  }

  node.className = "popover";
  node.innerText = "hello world hello world";
  event.srcElement.appendChild(node);
}

Snipet:

var popUpWidth = 60;
var containerWidth = 200;
function myclick(element) {
  let node = document.createElement("div");

  if(element.offsetLeft + popUpWidth > containerWidth){
     node.style.left = -20 + "px";
  }

  node.className = "popover";
  node.innerText = "hello world hello world";
  event.srcElement.appendChild(node);
}
.container {
  width: 230px;
  height: 200px;
  border: 1px solid #ddd;
  display: flex;
  flex-flow: wrap;
}

.tag {
  border: 1px solid #ddd;
  padding: 5px;
  margin: 5px;
  display: flex;
  height: 20px;
  position: relative;
}

.popover {
  position: absolute;
  top: 30px;
  width: 60px;
  left: 0px;
  background-color: #dfdfdf;
}
<div class="container">
  <div class="tag" onclick="myclick(this);">apple</div>
  <div class="tag" onclick="myclick(this);">banana</div>
  <div class="tag" onclick="myclick(this);">carrot</div>
  <div class="tag" onclick="myclick(this);">dog</div>
  <div class="tag" onclick="myclick(this);">elephant</div>
  <div class="tag" onclick="myclick(this);">firetruck</div>
</div>

Upvotes: 2

David Skx
David Skx

Reputation: 131

Just decrement the left position slightly:

.popover {
  position: absolute;
  top: 30px;
  width: 60px;
  left: -19px;
  background-color: #dfdfdf;
}

Upvotes: 0

Related Questions