skip to Main Content

the problem

I am trying to add some options on top of Twitter UI for text editing, but when I do that, I get an issue, and I cannot show the element on top of other elements. It’s always being shown behind the siblings.

The code

Here is the code I am trying and running it on https://twitter.com/home

let tweetArea = document.querySelector(".public-DraftStyleDefault-block");

const unlistedItems = document.createElement('ul');
unlistedItems.innerHTML += `
  <li> Option 0</li>
  <li> Option 1</li>
  <li> Option 2</li>
  <li> Option 3</li>`;
unlistedItems.style.position = 'absolute';
unlistedItems.style.top = '0';
unlistedItems.style.backgroundColor = "red";
unlistedItems.style.zIndex = '100';

tweetArea.parentNode.insertBefore(unlistedItems, tweetArea);

The current vs desired behavior:

I am getting this result which adds the element but it does not show it on top of the siblings and parents. I want my element to be visible and shown even on top of the Gif icon and toolbar. How can I achieve that?

enter image description here

What did I try?

As for this I tried to use Z-index but it did not work and could not figure out what is the reason even though I used a really high one.

Questions that I checked:

2

Answers


  1. Chosen as BEST ANSWER

    The solution

    The main issue I faced here was the stackedContext as what nkemdi and chris explained. To get over this issue, I have appended the element to the body directly. Then, I calculated the position of the element I want to position on top of it and added my element on top of that. Here is the solution:

    code

    // get the tweet text box to append the element on top of it.
    let tweetArea = document.querySelector(".public-DraftStyleDefault-block");
    
    let position = tweetArea.getBoundingClientRect(); // get the size and position related to view port of the element. 
    
    // create a list to add to the HTML page.
    const unlistedItems = document.createElement('ul');
    unlistedItems.innerHTML += `
      <li> Option 0</li>
      <li> Option 1</li>
      <li> Option 2</li>
      <li> Option 3</li>`;
    unlistedItems.style.position = 'absolute';
    
    // add the XY positions to the newly created element. 
    unlistedItems.style.top = position.y + "px";
    unlistedItems.style.left = position.x + "px"; 
    
    // add background color for visibility. The z-index could be ignored. 
    unlistedItems.style.backgroundColor = "red";
    unlistedItems.style.zIndex = '100';
    
    document.body.append(unlistedItems);
    

    Result:

    Here is the result of this code: enter image description here

    Limitation:

    The code above checks the position based on the view that's available when executed. If you want to keep the position constant, you need to do further coding for that to check the edge cases. Since it's out of the scope of this question, we will not dive into that.

    Further reading:


  2. The issue is related to stacking contexts and how parents with z-index affect their children. You could try moving your list of items further up the tree so that it is not nested so deeply, moving it to a spot where its z-index is not being scoped. Of course, you would need to figure out how to get it into the right spot on the screen.

    Explanation

    Suppose you have the following:

    .parent {
      position: relative;
      z-index: 20;
      width: 10rem;
      height: 10rem;
      background-color: blue;
    }
    
    .child {
      position: absolute;
      top: 8rem;
      z-index: 1000;
      width: 5rem;
      height: 5rem;
      background-color: red;
    }
    
    .extra {
      position: relative;
      z-index: 20;
      width: 10rem;
      height: 10rem;
      background-color: black;
    }
    <div class="parent">
      <div class="child"></div>
    </div>
    <div class="extra"></div>

    Notice how even though .child has z-index: 1000, it still goes underneath .extra? That’s because the z-index on .parent is explicitly less than or equal to the z-index on .extra. The result is that .child‘s z-index is essentially "scoped" to .parent, and since .parent and .extra have the same z-index in this example, .extra shows up in front because it is lower in the HTML code.

    Meanwhile, in the snippet below, z-index is unset on .parent and .extra. Now all of a sudden, .child is brought in front of .extra because its z-index is not being "scoped", if that makes sense. In your Twitter example, if you find your <ul> and start going up through its parents and removing their position styles (because z-index only affects positioned elements), you’ll notice that the list will eventually start to show through. That’s because of the exact same reason above.

    .parent {
      position: relative;
    /*   z-index: 20; */
      width: 10rem;
      height: 10rem;
      background-color: blue;
    }
    
    .child {
      position: absolute;
      top: 8rem;
      z-index: 1000;
      width: 5rem;
      height: 5rem;
      background-color: red;
    }
    
    .extra {
      position: relative;
    /*   z-index: 20; */
      width: 10rem;
      height: 10rem;
      background-color: black;
    }
    <div class="parent">
      <div class="child"></div>
    </div>
    <div class="extra"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search