With iOS 11 safari, input textbox cursor are outside of input textbox. We did not get why it is having this problem. As you can see my focused text box is email text input but my cursor is outside of it. This only happens with iOS 11 Safari
-
1This is a bug with Safari. Apple has fixed it internally but the fix is not in a public (or even beta) release of iOS yet. https://bugs.webkit.org/show_bug.cgi?id=176896 – Beetle Jan 11 '18 at 14:24
14 Answers
I fixed the issue by adding position:fixed
to the body when opening a modal.
Hope this will help you.

- 7,356
- 22
- 30

- 742
- 6
- 2
-
6Note per answers below -- Bootstrap adds .modal-open to body when the modal is open, so you can simply add position: fixed to that class. – timmyc Oct 11 '17 at 16:50
-
1You might also need to add `width:100%` to constrain the body width to the device width. In some cases, depending on existing markup, that could be an issue. I also like the solution by @gentleboy (below) so as not to penalize other browsers without the problem, because when setting the body to fixed causes the body to scroll to the top, which is somewhat annoying. – Redtopia Nov 02 '17 at 18:40
-
Strangely, I had this issue with an application build with meteor-cordova. It seemed like any iOS device running v11+ had this issue. In my case I already had `position:fixed` applied to the body of the application. Instead I changed it to `position:absolute` on the `html` element and it fixed my issue. Thank you Jen! – Adam Ross Bowers Nov 17 '17 at 16:51
-
1This could be the end of modal forms for us. Even if Apple fixes the issue, it will then be up to the user to update their device to see the working form. Is there not an easier universal way to fix this? What about a poly fill? – Reado Dec 28 '17 at 00:26
-
Personally, position: fixed
scroll to top automatically. Quite annoying !
To avoid penalizing other devices and versions I apply this fix only to the appropriate versions of iOS.
**VERSION 1 - All modals fix**
For the javascript/jQuery
$(document).ready(function() {
// Detect ios 11_x_x affected
// NEED TO BE UPDATED if new versions are affected
var ua = navigator.userAgent,
iOS = /iPad|iPhone|iPod/.test(ua),
iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);
// ios 11 bug caret position
if ( iOS && iOS11 ) {
// Add CSS class to body
$("body").addClass("iosBugFixCaret");
}
});
For the CSS
/* Apply CSS to iOS affected versions only */
body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }
**VERSION 2 - Selected modals only**
I modified the function to fire only for selected modals with a class .inputModal
Only the modals with inputs should be impacted to avoid the scroll to top.
For the javascript/jQuery
$(document).ready(function() {
// Detect ios 11_x_x affected
// NEED TO BE UPDATED if new versions are affected
(function iOS_CaretBug() {
var ua = navigator.userAgent,
scrollTopPosition,
iOS = /iPad|iPhone|iPod/.test(ua),
iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);
// ios 11 bug caret position
if ( iOS && iOS11 ) {
$(document.body).on('show.bs.modal', function(e) {
if ( $(e.target).hasClass('inputModal') ) {
// Get scroll position before moving top
scrollTopPosition = $(document).scrollTop();
// Add CSS to body "position: fixed"
$("body").addClass("iosBugFixCaret");
}
});
$(document.body).on('hide.bs.modal', function(e) {
if ( $(e.target).hasClass('inputModal') ) {
// Remove CSS to body "position: fixed"
$("body").removeClass("iosBugFixCaret");
//Go back to initial position in document
$(document).scrollTop(scrollTopPosition);
}
});
}
})();
});
For the CSS
/* Apply CSS to iOS affected versions only */
body.iosBugFixCaret.modal-open { position: fixed; width: 100%; }
For the HTML Add the class inputModal to the modal
<div class="modal fade inputModal" tabindex="-1" role="dialog">
...
</div>
Nota bene The javascript function is now self-invoking
**UPDATE iOS 11.3 - Bug corrected **
As of iOS 11.3, the bug has been corrected. There is no need to test for OS 11_
in iOS11 = /OS 11_0|OS 11_1|OS 11_2/.test(ua);
But be careful as iOS 11.2 is still widely used (as of April 2018). See

- 1,690
- 19
- 33
-
I like this, but you might also want to add width:100%, which will constrain the body to 100% of the device width. Depending on existing markup, that might be an issue. – Redtopia Nov 02 '17 at 18:34
-
2Nice advice. I do not have this issue but I guess this might be global as answer. I’ll add it after I finish my beers – Mike Casan Ballester Nov 02 '17 at 18:40
-
-
3@gentleboy Why not use a REGEX to find any OS 11? So that way you wouldn't have to update each OS 11 update to your code? something like this `iOS11 = /OS 11_(\d{1,2})(_{0,1})(\d{1,2})/.test(us);` – T. Evans Nov 21 '17 at 18:02
-
@T.Evans Regex will not give much more performance value but is **less readable** ;-) – Mike Casan Ballester Nov 21 '17 at 18:47
-
1@RonakK it looks like it is still present in beta 11.2 and 11.3 according to [bugs.webkit.org](https://bugs.webkit.org/show_bug.cgi?id=176896) – Mike Casan Ballester Nov 21 '17 at 18:50
-
2@T.Evans that regex doesn't work. A correct regex might be something like this: `ios11 = /OS 11_(\d{1,2})/.test(ua);` – Abraham Dec 12 '17 at 15:15
-
2Position fixed will still take document / body scroll to top. I suggest to grab current scrollTop position on modal open and readd scrollTop value once modal closed. Like this https://jsfiddle.net/im4aLL/hmvget9x/1/ – HADI Jan 15 '18 at 06:03
-
-
1
-
Find out more details on https://hackernoon.com/how-to-fix-the-ios-11-input-element-in-fixed-modals-bug-aaf66c7ba3f8 – Swapnil Dalvi Mar 08 '18 at 07:33
-
I suggest you put the last "bug fix" part in the top of your answer : ) – jilykate Sep 18 '18 at 15:13
This issue goes beyond Bootstrap, and beyond just Safari. It is a full display bug in iOS 11 that occurs in all browsers. The fix above does not fix this issue in all instances.
The bug is reported in detail here:
https://medium.com/@eirik.luka/how-to-fix-the-ios-11-input-element-in-fixed-modals-bug-aaf66c7ba3f8
Supposedly they already reported it to Apple as a bug.

- 151
- 6
-
This seems to be the issue for me, was working fine before updating to IOS 11. Android users aren't having the problem. – hackingchemist Oct 18 '17 at 15:55
Frustrating bug, thanks for identifying it. Otherwise, I would be banging my iphone or my head against the wall.
The simplest fix is (1 line of code change):
Just add the following CSS to the html or to an external css file.
<style type="text/css">
.modal-open { position: fixed; }
</style>
Here is a full working example:
.modal-open { position: fixed; }
<link href="https://getbootstrap.com/docs/3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@mdo">Open modal for @mdo</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@fat">Open modal for @fat</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@getbootstrap">Open modal for @getbootstrap</button>
...more buttons...
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="exampleModalLabel">New message</h4>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="recipient-name" class="control-label">Recipient:</label>
<input type="text" class="form-control" id="recipient-name">
</div>
<div class="form-group">
<label for="message-text" class="control-label">Message:</label>
<textarea class="form-control" id="message-text"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Send message</button>
</div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://getbootstrap.com/docs/3.3/dist/js/bootstrap.min.js"></script>
I submitted an issue here: https://github.com/twbs/bootstrap/issues/24059

- 421
- 4
- 8
-
This should be the answer. Bootstrap adds the modal-open class to the body when a modal is visible. You just need to target that class. – lfkwtz Oct 03 '17 at 21:01
-
1I have been dealing with this issue for some time. This solution is inadequate for me as adding position fixed scrolls the page back to the top. So when the user closes the modal, they are at a different scroll position. This leads to a terrible user experience – Nearpoint Oct 14 '17 at 22:25
-
This fix worked for me in using Chrome on mobile. Was confused at first since .modal-open does not appear in the modal html, but I added it anyway as CSS in my header and it worked. – David Dec 21 '17 at 12:41
Easiest/cleanest solution:
body.modal-open { position: fixed; width: 100%; }

- 1,007
- 2
- 11
- 25
-
1This is the easiest solution, and it works, but the only problem is the cursor disappears altogether. It's not as bad as the initial situation, but there's a usability problem. – tmo256 Nov 10 '17 at 21:18
-
-
1I also experienced the disappearing cursor, any thoughts as to why that could happen? – Alex Burgos Dec 05 '17 at 22:22
-
4Yeah I'm also seeing a disappearing cursor for just the first focus event. Subsequent input focuses have the cursor appearing. Very strange. This is only happening in Safari on iOS. – Devin Walker Dec 07 '17 at 01:16
-
-
-
I confirm this disappearing cursor bug and it looks like it's caused by using `position: fixed` on body. I fixed it by using `body { position: relative; }`, `html, body { overflow: hidden }` and instead of correcting top position for body, I use `position: absolute` on modal and use top position correction on modal. I'm going to add a response as well. – FlavioEscobar Mar 02 '18 at 21:51
This issue is no longer reproducible after updating your apple devices to iOS 11.3
-
-
1@Starscream yes it's fixed by apple with this software version (iOS 11.3) – Eashan Apr 10 '18 at 06:22
Add position: fixed;
to body
when modal is open.
$(document).ready(function($){
$("#myBtn").click(function(){
$("#myModal").modal("show");
});
$("#myModal").on('show.bs.modal', function () {
$('body').addClass('body-fixed');
});
$("#myModal").on('hide.bs.modal', function () {
$('body').removeClass('body-fixed');
});
});
.body-fixed {
position: fixed;
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<button type="button" class="btn btn-info btn-lg" id="myBtn">Open Modal</button>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Form</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label class="control-label">Input #1</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label class="control-label">Input #2</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label class="control-label">Input #3</label>
<input type="text" class="form-control">
</div>
<div class="form-group">
<label class="control-label">Input #4</label>
<input type="text" class="form-control">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

- 29
- 2
-
1Similar to other solutions on this thread, once the modal closes - you're back at the top again. For example: user scrolls through grid of items, launches details in a modal.. and with this fix, when they close the modal.. they are once again at the top of the grid of items again and must re-scroll – bkwdesign Dec 20 '17 at 19:19
-
2on my iPhone 7 plus, this fix causes my cursor to disappear altogether – bkwdesign Dec 20 '17 at 19:20
Those solutions using position: fixed
and position correction based on scrollTop
work really well, but some people (including me) got another issue: keyboard caret/cursor not showing when inputs are focused.
I observed that caret/cursor works only when we DON'T use position: fixed
on body. So after trying several things, I gave up on using this approach and decided to use position: relative
on body
and use scrollTop
to correct modal's top position instead.
See code below:
var iosScrollPosition = 0;
function isIOS() {
// use any implementation to return true if device is iOS
}
function initModalFixIOS() {
if (isIOS()) {
// Bootstrap's fade animation does not work with this approach
// iOS users won't benefit from animation but everything else should work
jQuery('#myModal').removeClass('fade');
}
}
function onShowModalFixIOS() {
if (isIOS()) {
iosScrollPosition = jQuery(window).scrollTop();
jQuery('body').css({
'position': 'relative', // body is now relative
'top': 0
});
jQuery('#myModal').css({
'position': 'absolute', // modal is now absolute
'height': '100%',
'top': iosScrollPosition // modal position correction
});
jQuery('html, body').css('overflow', 'hidden'); // prevent page scroll
}
}
function onHideModalFixIOS() {
// Restore everything
if (isIOS()) {
jQuery('body').css({
'position': '',
'top': ''
});
jQuery('html, body').scrollTop(iosScrollPosition);
jQuery('html, body').css('overflow', '');
}
}
jQuery(document).ready(function() {
initModalFixIOS();
jQuery('#myModal')
.on('show.bs.modal', onShowModalFixIOS)
.on('hide.bs.modal', onHideModalFixIOS);
});

- 839
- 1
- 12
- 19
As previously mentioned: setting the style.position
property
of body
to fixed
solves the iOS cursor misplacement
issue.
However, this gain comes at the cost of being forcibly scrolled to the top of the page.
Fortunately, this new UX
problem can be negated without much overhead by leveraging HTMLElement.style
and window.scrollTo()
.
The basic gist is to counteract the scroll to top
by manipulating the body
element's style.top
when mounting
. This is done using the YOffset
value captured by the ygap
variable.
From there it's simply a matter of resetting the body's
style.top
to 0
and reframing the user's view using window.scrollTo(0, ygap)
when dismounting
.
See below for a practical example.
// Global Variables (Manage Globally In Scope).
const body = document.querySelector('body') // Body.
let ygap = 0 // Y Offset.
// On Mount (Call When Mounting).
const onModalMount = () => {
// Y Gap.
ygap = window.pageYOffset || document.documentElement.scrollTop
// Fix Body.
body.style.position = 'fixed'
// Apply Y Offset To Body Top.
body.style.top = `${-ygap}px`
}
// On Dismount (Call When Dismounting).
const onModalDismount = () => {
// Unfix Body.
body.style.position = 'relative'
// Reset Top Offset.
body.style.top = '0'
// Reset Scroll.
window.scrollTo(0, ygap)
}

- 5,669
- 2
- 22
- 32
-
Do you have a more detailed example for this? I'm guessing I would have the Mount in a function that is called when the modal opens, and then put the Dismount in a function and call that when the modal is closed. – Neal Jones Jan 10 '18 at 17:57
-
Aahh yep. I see what you mean. Please see above for a revised solution. Also; yes the intent is for you to call those `functions` when `mounting` and `dismounting`. Thanks. – Arman Charan Jan 11 '18 at 00:15
Incase anyone is looking for a fix in vanilla js that works on IOS >11.2 and doesnt require any additional CSS:
(function() {
if (!/(iPhone|iPad|iPod).*(OS 11_[0-2]_[0-5])/.test(navigator.userAgent)) return
document.addEventListener('focusin', function(e) {
if (!e.target.tagName == 'INPUT' && !e.target.tagName != 'TEXTAREA') return
var container = getFixedContainer(e.target)
if (!container) return
var org_styles = {};
['position', 'top', 'height'].forEach(function(key) {
org_styles[key] = container.style[key]
})
toAbsolute(container)
e.target.addEventListener('blur', function(v) {
restoreStyles(container, org_styles)
v.target.removeEventListener(v.type, arguments.callee)
})
})
function toAbsolute(modal) {
var rect = modal.getBoundingClientRect()
modal.style.position = 'absolute'
modal.style.top = (document.body.scrollTop + rect.y) + 'px'
modal.style.height = (rect.height) + 'px'
}
function restoreStyles(modal, styles) {
for (var key in styles) {
modal.style[key] = styles[key]
}
}
function getFixedContainer(elem) {
for (; elem && elem !== document; elem = elem.parentNode) {
if (window.getComputedStyle(elem).getPropertyValue('position') === 'fixed') return elem
}
return null
}
})()
What this does is:
- Check if the browser is Safari on iOS 11.0.0 - 11.2.5
- Listen for any
focusin
events on the page - If the focused element is an
input
or atextarea
and is contained in an element withfixed
position, change the container position toabsolute
while regardingscrollTop
and the containers original dimensions. - On blur, restore the container's position to
fixed
.

- 6,410
- 1
- 18
- 25
This solution worked for me and its working well across all browsers on iOS.
.safari-nav-force{
/* Allows content to fill the viewport and go beyond the bottom */
height: 100%;
overflow-y: scroll;
/* To smooth any scrolling behavior */
-webkit-overflow-scrolling: touch;
}
JavsScript
var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
$('.modal').on('shown.bs.modal', function () {
if (iOS && $('.modal').hasClass('in')){
$('html,body').addClass('safari-nav-force');
}
});
$('.modal').on('hidden.bs.modal', function () {
if (iOS && !$('.modal').hasClass('in')){
$('html,body').removeClass('safari-nav-force');
}
});
Have you try viewport-fit=cover for the meta viewport.
Look at this : https://ayogo.com/blog/ios11-viewport/

- 71
- 2
- 8
Override modal css and change its position
from fixed
to absolute
.modal {
position: absolute !important;
}

- 1
- 1
-
1Didn't work in my scenario. Changing fixed to absolute can have MANY knock on effects – Steve D Nov 09 '17 at 13:55
-
@SteveD - to make it work you should append your modal to . And the should have - position: relative. And when it should work :) – Dan Nov 22 '17 at 09:37
add to the #modal position:absolute it fix future issues related to the position: fixed

- 1
- 1
-
Your answer is an exact duplicate. Please make sure not to post duplicate answers. – MechMK1 Dec 20 '17 at 20:08