Q:

CSS: position element outside of area without changing scrollbar

I have a modal dialog which has a vertical scrollbar that appears when the modal contents are too large to be contained.
My problem is: when a control (actually a Twitter Typeahead https://twitter.github.io/typeahead.js/) that I want to "popout" of the modal appears, it causes the scrollbar on the modal to extend.
Probably best explained by example:
Desired behaviour
https://jsfiddle.net/0eara5xc/14/ shows the behaviour I want (enter the letter 'a' in the input box), however the modal does not scroll when the regular content is too large (which I need).
Undesired behaviour
As soon as I make the modal scrollable, the popup causes the scrollbar to increase.  
.modal-body {
    max-height: 40vh;
    overflow: hidden;
    overflow-y: auto;
}

https://jsfiddle.net/0eara5xc/13/ (scroll down and enter the letter 'a' in the input box)
I actually want the popup to flow outside of the modal as per the first example.
The Twitter Typeahead control creates its own position:relative and position:absolute elements, so I don't think I can use CSS to absolutely position the dynamically created popup elements.

A:

The issue here is that you want to have 2 things that are contradictory. I am going to explain with few examples until I reach my idea of solution.
If we take in-flow elements (a container and an inner element) we have two situtaion:
(1)  The height of the inner element is smaller or equal to the height of the container. In this case all the overflow (auto, scroll and hidden) are the same.
(2) The height of the inner element is bigger than the height of container and in this case we:

Keep the default behavior and we will have an overflow and we can see the element outside.

.el {
  border:5px solid green;
  height:100px;
}
.el > div {
  height:200px;
  width:100%;
  background:red;
}
<div class="el">
   <div>
   
   </div>
 </div>

Use overflow:hidden to hide some of the inner element so we cannot see the overflowing part. 

.el {
  border:5px solid green;
  height:100px;
  overflow:hidden;
}
.el > div {
  height:200px;
  width:100%;
  background:red;
}
<div class="el">
   <div>
   
   </div>
 </div>

Use overflow:scroll to hide some of the inner element and we can only see the overflowing part on scroll.

.el {
  border:5px solid green;
  height:100px;
  overflow:scroll;
}
.el > div {
  height:200px;
  width:100%;
  background:red;
}
<div class="el">
   <div>
   
   </div>
 </div>

So technically we cannot have the element overflowing with a scroll.

When using absolute:position we will be in the situation (2) almost in all the case (unless we define a big height for the container) because absolute positioned element is out of the flow and is not considered in the height calculation of the container so logically the height of inner elements will be bigger and the same logic above will apply:

.el {
  border:5px solid green;
  position:relative;
}
.el > div {
  height:100px;
  background:red;
}
.el > div:last-child {
  position:absolute;
  background:blue;
  right:0;
  left:0;
}
<div class="el">
   <div>
     we see the element
   </div>
   <div>
   
   </div>
 </div>

 <div class="el" style="overflow:hidden;margin-top:100px;">
   <div>
      we don't see the element
   </div>
   <div>
   
   </div>
 </div>
 
  <div class="el" style="overflow:scroll;">
   <div>
      we see the element element on scroll
   </div>
   <div>
   
   </div>
 </div>

The same logic also apply even if the overflow property is set to another element ancestor of the absolute positioned element. As you can read here:

In most cases, overflow can be computed for any box from the bounds
  and properties of that box itself, plus the overflow of each of its
children.

So using overflow:scroll will always make the scroll to increase when any child element is increasing in height or is having overflow AND there is no way to have any overflowing element outside since this is the default behavior and you change it by setting overflow:scroll.
The solution
The first easy solution to avoid the scroll to be applied to your element is to make the element positioned relative to an ancestor of the element on where you applied the scroll. In other words: between the element with overflow:scroll and the absolute postioned element you should not find any positioned element. As you can read in this complex statement here:

... a box may overflow, meaning its content lies partly or entirely
  outside of the box, e.g.:
[...]
A descendant box is positioned absolutely, partly outside the box.
  Such boxes are not always clipped by the overflow property on their
  ancestors; specifically, they are not clipped by the overflow of any
  ancestor between themselves and their containing block

This solution will of course break your code.

The other idea is to make the element position:fixed. Like this it will be relative to browser window and we can see it outside the scroll BUT it will be difficult to adjust its position using CSS. In this case we can consider some JS to dynamically adjust the position of the element:
$('.typeahead').on('keypress change',function(e){
  var y = $(this).offset().top + $(this).height();
  var x = $(this).offset().left;
  $('.tt-menu').css('top',y);
  $('.tt-menu').css('left',x);
})

As you can see, we simply calculate the top/left position of the element based on the position of the input.
Here is the full code:

$(function () {
$('.typeahead').on('keypress change',function(e){
  var y = $(this).offset().top + $(this).height()+5;
  var x = $(this).offset().left;
  $('.tt-menu').css('top',y);
  $('.tt-menu').css('left',x);
})



  $('#btnPopup').on('click', function(){
   $('#divPopup').toggle();
  });
  
  var substringMatcher = function(strs) {

  return function findMatches(q, cb) {

    var matches, substringRegex;



    // an array that will be populated with substring matches

    matches = [];



    // regex used to determine if a string contains the substring `q`

    substrRegex = new RegExp(q, 'i');



    // iterate through the pool of strings and for any string that

    // contains the substring `q`, add it to the `matches` array

    $.each(strs, function(i, str) {

      if (substrRegex.test(str)) {

        matches.push(str);

      }

    });



    cb(matches);

  };

};



var states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',

  'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii',

  'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana',

  'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota',

  'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire',

  'New Jersey', 'New Mexico', 'New York', 'North Carolina', 'North Dakota',

  'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island',

  'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont',

  'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'

];



$('.typeahead').typeahead({

  hint: true,

  highlight: true,

  minLength: 1

},

{

  name: 'states',

  source: substringMatcher(states)

});
  
});
.modal-body {
  
 max-height: 40vh;
 overflow: hidden;
 overflow-y: auto;
}

.modal-header, .modal-footer {
  background-color: black;
  color: white;
}

#divSpacer {
  height: 40vh;
  background-color: rgb(220, 220, 220);
}

.tt-menu {
  background-color: red;
  position:fixed!important;
}
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<link rel="stylesheet" type="text/css" href="/css/result-light.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"></script>
<div>
  <div class="modal-lg">
    <div class="modal-header">
      My modal title
    </div>
    <div class="modal-body">
      <div id="divSpacer">
        Lots of space taken up here...
      </div>
      
       <input class="typeahead" type="text" placeholder="States of USA">
      
    </div>
    <div class="modal-footer">
    </div>
  </div>
</div>

