Search code examples
htmlcsshtml5-draggable

Allow select text on a HTML 5 draggable child element


Having a table with draggable rows where each row is draggable=true, how can the user still be able to select text from a column?

<table>
 <thead>..</thead>
 <tbody>
  ..
  <tr draggable="true">
   <td>..</td>
   <td>Cool text but you can't select me</td>
   <td>..</td>
  </tr>
  ..
</tbody>
</table>

Another simple example (https://codepen.io/anon/pen/qjoBXV)

div {
  padding: 20px;
  margin: 20px;
  background: #eee;
}

.all-copy p {  
  -webkit-user-select: all;  /* Chrome all / Safari all */
  -moz-user-select: all;     /* Firefox all */
  -ms-user-select: all;      /* IE 10+ */
  user-select: all;          /* Likely future */   
}    
<div class="all-copy" draggable="true">
      <p>Select me as text</p>
    </div>

Solution

  • One way to make that work, is to actually check which element fired the event, e.target, against the element that has the listener attach to itself, #draggable (in this case using this).

    if (e.target === this) {...}
    

    This will allow default behavior on element positioned inside the draggable element, such as selecting a text and so on.

    Note, since Firefox has issue with draggable="true", I used a different drag method.

    Stack snippet

    (function (elem2drag) {
      var x_pos = 0, y_pos = 0, x_elem = 0, y_elem = 0;  
      
      document.querySelector('#draggable').addEventListener('mousemove', function(e) {
        x_pos = e.pageX;
        y_pos = e.pageY;
        if (elem2drag !== null) {
            elem2drag.style.left = (x_pos - x_elem) + 'px';
            elem2drag.style.top = (y_pos - y_elem) + 'px';
        }  
      })
    
      document.querySelector('#draggable').addEventListener('mousedown', function(e) {
        if (e.target === this) {
          elem2drag = this;
          x_elem = x_pos - elem2drag.offsetLeft;
          y_elem = y_pos - elem2drag.offsetTop;
          return false;
        }  
      })
      
      document.querySelector('#draggable').addEventListener('mouseup', function(e) {
        elem2drag = null;
      })
    })(null);
    #draggable {
      display: inline-block;
      background: lightgray;
      padding:15px;
      cursor:move;
      position:relative;
    }
    span {
      background: white;
      line-height: 25px;
      cursor:auto;  
    }
    <div id="draggable">
      <span>Select me as text will work<br>when the mouse is over the text</span>
    </div>