diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index b9f6658..b9bd53e 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -4,6 +4,7 @@ X-editable changelog
 
 Version 1.5.1 wip
 ----------------------------
+[enh #396] bs3 popover: placement `auto` (vitalets)
 [bug #357] select2: tags mode with space separator (vitalets)
 [bug #374] dateui: clear button does not submit (vitalets)
 
diff --git a/src/containers/editable-popover3.js b/src/containers/editable-popover3.js
index dc37ba5..f1fac8c 100644
--- a/src/containers/editable-popover3.js
+++ b/src/containers/editable-popover3.js
@@ -180,16 +180,41 @@
             var placement = typeof this.options.placement == 'function' ?
                 this.options.placement.call(this, $tip[0], this.$element[0]) :
                 this.options.placement;            
+
+            var autoToken = /\s?auto?\s?/i;
+            var autoPlace = autoToken.test(placement);
+            if (autoPlace) placement = placement.replace(autoToken, '') || 'top';
             
             
             var pos = this.getPosition();
             var actualWidth = $tip[0].offsetWidth;
             var actualHeight = $tip[0].offsetHeight;
+
+            if (autoPlace) {
+                var $parent = this.$element.parent();
+
+                var orgPlacement = placement;
+                var docScroll    = document.documentElement.scrollTop || document.body.scrollTop;
+                var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth();
+                var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight();
+                var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left;
+
+                placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
+                            placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
+                            placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
+                            placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
+                            placement;
+
+                $tip
+                  .removeClass(orgPlacement)
+                  .addClass(placement);
+            }
+
+
             var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight);
 
             this.applyPlacement(calculatedOffset, placement);            
-           
-           
+                     
                 
             }).call(this.container());
           /*jshint laxcomma: false, eqeqeq: true*/  
diff --git a/test/unit/common.js b/test/unit/common.js
index 1360d38..a0b93c8 100644
--- a/test/unit/common.js
+++ b/test/unit/common.js
@@ -88,7 +88,31 @@
         //check title
         ok(p.find(':contains("'+title+'")').length, 'title ok');
         e.remove();
-      });   
+      });
+
+    test("popup placement `auto` (BS3 only)", function () {
+        //do not test inline  
+        if($.fn.editable.defaults.mode === 'inline' || $.fn.editableform.engine !== 'bs3') {
+            expect(0);
+            return;
+        }
+        
+        var title = 'abc',
+        //add to fx because qunit-fixture has wrong positioning
+        e = $('<a href="#" id="a" style="position: absolute; top: 50px; left: 10px"></a>').appendTo(fx).editable({
+              placement: 'auto',
+              title: title
+        });
+
+        e.click();
+        var p = tip(e); 
+        ok(p.is(':visible'), 'popover shown');   
+
+        ok(p.offset().left < e.offset().left, 'placement X ok');
+        ok(p.offset().top > e.offset().top, 'placement Y ok');
+
+        e.remove();
+      });     
       
       test("onblur: cancel", function () {
         var oldValue = 'abc',