122

Any idea how to get the DatePicker to appear at the end of the associated text box instead of directly below it? What tends to happen is that the text box is towards the bottom of the page and the DatePicker shifts up to account for it and totally covers the text box. If the user wants to type the date instead of pick it, they can't. I'd rather have it appear just after the text box so it doesn't matter how it adjusts vertically.

Any idea how to control the positioning? I didn't see any settings for the widget, and I haven't had any luck tweaking the CSS settings, but I could easily be missing something.

Athafoud
  • 2,898
  • 3
  • 40
  • 58
gfrizzle
  • 12,419
  • 19
  • 78
  • 104

24 Answers24

126

Here's what I'm using:

$('input.date').datepicker({
    beforeShow: function(input, inst) {
        inst.dpDiv.css({
            marginTop: -input.offsetHeight + 'px', 
            marginLeft: input.offsetWidth + 'px'
        });
    }
});

You may also want to add a bit more to the left margin so it's not right up against the input field.

Mr.Singh
  • 1,421
  • 6
  • 21
  • 46
  • 2
    Good trick. Problem is that in cases where the datepicker is shown beyond screen borders, the _showDatepicker will try to relocate it, therefore, top and left will be different and marginTop, marginLeft might need tuning. – monzonj Jun 29 '11 at 10:00
  • 1
    I used a similar approach--I took your idea of using beforeShow, but my beforeShow function uses JQueryUI's position effect: `$(this).position(my:'left top', at:'left bottom', of:'#altField')` (since I'm using datepicker's `altField` option for display) – Isaac Betesh Mar 13 '14 at 19:50
  • This may work to set margins, but fails for "left", "top", "z-index", and "position" attributes. – aaronbauman Mar 18 '14 at 21:58
  • As I understand it, this doesn't work either, because jquery resets the position after the beforeShow is called. – Software Engineer Nov 25 '14 at 20:28
  • The given answer *is* wrong cause datepicker will reset the position after beforeShow() returned. – wh81752 Jul 16 '15 at 10:20
43

I do it directly in the CSS:

.ui-datepicker { 
  margin-left: 100px;
  z-index: 1000;
}

My date input fields are all 100px wide. I also added the z-index so the calendar also appears above AJAX popups.

I don't modify the jquery-ui CSS file; I overload the class in my main CSS file, so I can change the theme or update the widget without having to re-enter my specific mods.

Christian Lescuyer
  • 18,893
  • 5
  • 49
  • 45
  • Same issue as the other css-trick: Only works if you now exactly where the datepicker should be in CSS. You cannot use this method to dynamically place the datepicker. I had to use a hack, binding on inst.input.focus() – aaronbauman Mar 18 '14 at 21:58
  • Worked for me using Bootstrap :) but I only set the z-index property. – Francisco Goldenstein Sep 09 '14 at 18:32
  • Useless for anything other than trivial implementations as you'll not know where the input field is on the page. – Software Engineer Nov 25 '14 at 20:28
42

Here is my variation of Datepicker calendar aligning.

I think that it's pretty nice, because you can control positioning via jQuery UI Position util.

One restriction: jquery.ui.position.js required.

Code:

$('input[name=date]').datepicker({
    beforeShow: function(input, inst) {
        // Handle calendar position before showing it.
        // It's not supported by Datepicker itself (for now) so we need to use its internal variables.
        var calendar = inst.dpDiv;

        // Dirty hack, but we can't do anything without it (for now, in jQuery UI 1.8.20)
        setTimeout(function() {
            calendar.position({
                my: 'right top',
                at: 'right bottom',
                collision: 'none',
                of: input
            });
        }, 1);
    }
})
Tony O'Hagan
  • 21,638
  • 3
  • 67
  • 78
Rost
  • 3,602
  • 2
  • 21
  • 21
34

Here is another variation that works well for me, adjust the rect.top + 40, rect.left + 0 to suit your needs:

$(".datepicker").datepicker({
    changeMonth: true,
    changeYear: true,
    dateFormat: 'mm/dd/yy',
    beforeShow: function (input, inst) {
        var rect = input.getBoundingClientRect();
        setTimeout(function () {
         inst.dpDiv.css({ top: rect.top + 40, left: rect.left + 0 });
        }, 0);
    }
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<form>
<input class="datepicker" name="date1" type="text">
<input class="datepicker" name="date2" type="text">
</form>
Patrick Montelo
  • 2,211
  • 1
  • 20
  • 14
20

The accepted answer for this question is actually not for the jQuery UI Datepicker. To change the position of the jQuery UI Datepicker just modify .ui-datepicker in the css file. The size of the Datepicker can also be changed in this way, just adjust the font size.

Earlz
  • 62,085
  • 98
  • 303
  • 499
jonmc12
  • 562
  • 8
  • 11
  • Not sure why I originally accepted Kev's answer, because that's not how I solved my problem. I modified .ui-datepicker as described above. Must have been a long night. :) – gfrizzle Feb 01 '11 at 21:29
  • 4
    Could you please tell me tell me which changes you made? – eddy May 18 '11 at 23:28
  • 1
    @gfrizzle - yep, that answer of mine was just so wrong. Finally got around to binning it. No idea what I was thinking of back then :/ – Kev Jun 06 '11 at 21:23
  • 1
    This only works if you now exactly where the datepicker should be in CSS. You cannot use this method to dynamically place the datepicker. I had to use a hack, binding on inst.input.focus() – aaronbauman Mar 18 '14 at 21:57
  • 76
    I have no idea why this is the accepted answer as it's almost completely useless. – Software Engineer Nov 25 '14 at 20:27
  • 15
    The given answer *is* completely useless as datepicker will dynamically modifies .ui-datepicker's css before popping up the widget. – wh81752 Jul 16 '15 at 10:19
  • 5
    This answer does not give any details, and should not be the accepted answer. – chapeljuice Dec 04 '18 at 18:54
18

This works for me:

beforeShow: function(input, inst) {
    var $this = $(this);
    var cal = inst.dpDiv;
    var top = $this.offset().top + $this.outerHeight();
    var left = $this.offset().left;

    setTimeout(function() {
        cal.css({
            'top': top,
            'left': left
        });
    }, 10);
}
Mr.Singh
  • 1,421
  • 6
  • 21
  • 46
David Laberge
  • 15,435
  • 14
  • 53
  • 83
8

First I think there should be a afterShowing method in the datepicker object, where you could change the position after jquery has done all its voodoo in the _showDatepicker method. Additionally, a parameter called preferedPosition would be also desirable, so you could set it and jquery modify it in case the dialog is rendered outside the viewport.

There's a "trick" to do this last thing. If you study the _showDatepicker method, you will see the use of a private variable $.datepikcer._pos. That variable will be setup if nobody has set it up before. If you modify that variable before showing the dialog, Jquery will take it and will try to allocate the dialog in that position, and if it renders out of the screen, it will adjust it to make sure it is visible. Sounds good, eh?

Problem is; _pos is private, but if you don't mind that. You can:

$('input.date').datepicker({
    beforeShow: function(input, inst)
    {
        $.datepicker._pos = $.datepicker._findPos(input); //this is the default position
        $.datepicker._pos[0] = whatever; //left
        $.datepicker._pos[1] = whatever; //top
    }
});

But be careful of Jquery-ui updates, because a change in the internal implementation of the _showDatepicker might break your code.

monzonj
  • 3,659
  • 2
  • 32
  • 27
4

I needed to position the datepicker according to a parent div within which my borderless input control resided. To do it, I used the "position" utility included in jquery UI core. I did this in the beforeShow event. As others commented above, you can't set the position directly in beforeShow, as the datepicker code will reset the location after finishing the beforeShow function. To get around that, simply set the position using setInterval. The current script will complete, showing the datepicker, and then the repositioning code will run immediately after the datepicker is visible. Though it should never happen, if the datepicker isn't visible after .5 seconds, the code has a fail-safe to give up and clear the interval.

        beforeShow: function(a, b) {
            var cnt = 0;
            var interval = setInterval(function() {
                cnt++;
                if (b.dpDiv.is(":visible")) {
                    var parent = b.input.closest("div");
                    b.dpDiv.position({ my: "left top", at: "left bottom", of: parent });
                    clearInterval(interval);
                } else if (cnt > 50) {
                    clearInterval(interval);
                }
            }, 10);
        }
  • Very ugly solution. Biggest problem would be a noticeable "jump" of the datepicker widget just after it got visible where suddenly your "relocation" kicks in. To be avoided at all costs. – wh81752 Jul 16 '15 at 10:29
3

bind focusin after using datepicker change css of datepicker`s widget wish help

$('input.date').datepicker();
$('input.date').focusin(function(){
    $('input.date').datepicker('widget').css({left:"-=127"});
});
anubiskong
  • 1,733
  • 1
  • 13
  • 6
3

A very simple jquery function.

$(".datepicker").focus(function(event){
                var dim = $(this).offset();
                $("#ui-datepicker-div").offset({
                    top     :   dim.top - 180,
                    left    :   dim.left + 150
                });
            });
Harry
  • 1,572
  • 2
  • 17
  • 31
3

i fixed it with my custom jquery code.

  1. gave my datepicker input field a class ".datepicker2"

  2. find its current position from top and

  3. positioned the popup box, which class name is ".ui-datepicker"

here is my code.

$('.datepicker2').click(function(){
    var popup =$(this).offset();
    var popupTop = popup.top - 40;
    $('.ui-datepicker').css({
      'top' : popupTop
     });
});

here "40" is my expected pixel, you may change with yours.

sh6210
  • 4,190
  • 1
  • 37
  • 27
2

I spent a ridiculous amount of time trying to figure this problem out for several pages of a new site I'm developing and nothing seemed to work (including any of the various solutions presented above that I implemented. I'm guessing jQuery has just changed things up enough since they were suggested that the solutions dont' work any longer. I don't know. Honestly, I don't understand why there isn't something simple implemented into the jQuery ui to configure this, as it seems to be a fairly large issue with the calendar always popping up at some position considerably far down the page from the input to which it is attached.

Anyhow, I wanted an end solution that was generic enough that I could use it anywhere and it would work. I seem to have finally come to a conclusion that avoids some of the more complicated and jQuery-code-specific answers above:

jsFiddle: http://jsfiddle.net/mu27tLen/

HTML:

<input type="text" class="datePicker" />

JS:

positionDatePicker= function(cssToAdd) {
    /* Remove previous positioner */
    var oldScript= document.getElementById('datePickerPosition');
    if(oldScript) oldScript.parentNode.removeChild(oldScript);
    /* Create new positioner */
    var newStyle= document.createElement("style");
    newStyle.type= 'text/css';
    newStyle.setAttribute('id', 'datePickerPostion');
    if(newStyle.styleSheet) newStyle.styleSheet.cssText= cssToAdd;
    else newStyle.appendChild(document.createTextNode(cssToAdd));
    document.getElementsByTagName("head")[0].appendChild(newStyle);
}
jQuery(document).ready(function() {
    /* Initialize date picker elements */
    var dateInputs= jQuery('input.datePicker');
    dateInputs.datepicker();
    dateInputs.datepicker('option', {
        'dateFormat' : 'mm/dd/yy',
        'beforeShow' : function(input, inst) {
            var bodyRect= document.body.getBoundingClientRect();
            var rect= input.getBoundingClientRect();
            positionDatePicker('.page #ui-datepicker-div{z-index:100 !important;top:' + (rect.top - bodyRect.top + input.offsetHeight + 2) + 'px !important;}');
        }
    }).datepicker('setDate', new Date());
});

Essentially I attach a new style tag to the head prior to every datepicker "show" event (deleting the previous one, if present). This method of doing things gets around a large majority of the issues that I ran into during development.

Tested on Chrome, Firefox, Safari, and IE>8 (as IE8 doesn't work well with jsFiddle and I'm losing my gusto for caring about

I know that this is a mix of jQuery and javascript contexts, but at this point I just don't want to put the effort into converting it to jQuery. Would be simple, I know. I'm so done with this thing right now. Hope someone else can benefit from this solution.

Programmer Dan
  • 289
  • 2
  • 10
2

I took it from ((How to control positioning of jQueryUI datepicker))

$.extend($.datepicker, { 
    _checkOffset: function(inst, offset, isFixed) { 
        return offset 
    } 
});

it works !!!

Mr.Singh
  • 1,421
  • 6
  • 21
  • 46
masoud Cheragee
  • 350
  • 3
  • 9
2

Or you can use the focus event on your dateSelect object and position api together. You can swap top and bottom and left for right or center (or really anything you want from the position api). This way you don't need an interval or any insanely complex solution and you can configure the layout to suit your needs depending on where the input is.

dateSelect.focus(function () {
    $("#ui-datepicker-div").position({
        my: "left top",
        at: "left bottom",
        of: $(this)
    });
});
Taugenichts
  • 1,307
  • 12
  • 19
1

fix show position problem daterangepicker.jQuery.js

//Original Code
//show, hide, or toggle rangepicker
    function showRP() {
        if (rp.data('state') == 'closed') {
            rp.data('state', 'open');
            rp.fadeIn(300);
            options.onOpen();
        }
    }


//Fixed
//show, hide, or toggle rangepicker
    function showRP() {
        rp.parent().css('left', rangeInput.offset().left);
        rp.parent().css('top', rangeInput.offset().top + rangeInput.outerHeight());
        if (rp.data('state') == 'closed') {
            rp.data('state', 'open');
            rp.fadeIn(300);
            options.onOpen();
        }
    }
zersina
  • 44
  • 3
1

They changed the classname to ui-datepicker-trigger

So this works in jquery 1.11.x

.ui-datepicker-trigger { 
margin-top:7px;
  margin-left: -30px;
  margin-bottom:0px;
  position:absolute;
  z-index:1000;
}
jmoreno
  • 12,752
  • 4
  • 60
  • 91
Marc
  • 11
  • 1
1

The solution here: https://stackoverflow.com/a/10598178/19074969 solved the basic problem for me to position the datepicker on a specific side of the date input field. However, the problem remains to define an offset in order to finetune the position of the datepicker popup box. This seems to be easily accomplished by applying some css style transform translate to the datepicker div:

setTimeout(function() {
   jQuery("input[name='date']").datepicker({
      beforeShow: function(input, inst) {
         var calendar = inst.dpDiv;
         setTimeout(function () {
            calendar.position({
               my: 'left bottom',
               at: 'left top',
               collision: 'none',
               of: input
            });
            jQuery("#ui-datepicker-div").css('transform', 'translate( -40px, -10px )');
         }, 0);
      },
   });
}, 800);

Problem is, if you click somewhere else, the datepicker box disappears and if you click on the date input field again, jQuery recalculates and updates the position of the datepicker div before opening it and the effect of the css style transform translate is lost.

To tackle this, we need to reset the css style transform translate to zero each time the datepicker popup box is closed. In the following, a mutation observer is set up, like here: Javascript detect when computed css property changes, to watch for the event when the datepicker is closed while the CSS style attribute "display" changes to "none" and the css style transform translate can be resetted back to zero:

if ( !window.document.documentMode ) {                                                  // would break IE11
   setTimeout(function() {                                                              // after page is loaded, otherwise (input.hasDatepicker) would not be available
      if ( jQuery("input.hasDatepicker").length > 0 ) {
         var $observation_target = document.getElementById('ui-datepicker-div');
         let style = window.getComputedStyle($observation_target);
         var $mutation_observer = new MutationObserver(function(mutations){             // callback function
            mutations.forEach(function(mutation){
               if ( style.display === 'none' ) {
                  $observation_target.style.transform = 'translate( 0px, 0px )';
               } 
            });
         });
         $mutation_observer.observe( $observation_target , {attributes:true} );         // Start the mutation observer (options: What is observed? CSS style attributes!)
      }
   }, 800);
}

In both cases the "setTimeout" function is needed to wait until page load is complete, otherwise input.hasDatepicker does not yet exist and cannot be found. Adjust the delay (milliseconds) according to your speed of page load! Now, it works every time and the position of the datepicker div is adjusted after it is recalculated by jQuery.

The only limitation: the transform translate hack does not work with IE11. (Tested and works with Edge and Firefox!)

0

It's also worth noting that if IE falls into quirks mode, your jQuery UI components, and other elements, will be positioned incorrectly.

To make sure you don't fall into quirks mode, make sure you set your doctype correctly to the latest HTML5.

<!DOCTYPE html>

Using transitional makes a mess of things. Hopefully this will save someone some time in the future.

Halfstop
  • 1,710
  • 17
  • 34
0

This puts the functionality into a method named function, allowing for your code to encapsulate it or for the method to be made a jquery extension. Just used on my code, works perfectly

var nOffsetTop  = /* whatever value, set from wherever */;
var nOffsetLeft = /* whatever value, set from wherever */;

$(input).datepicker
(
   beforeShow : function(oInput, oInst) 
   { 
      AlterPostion(oInput, oInst, nOffsetTop, nOffsetLeft); 
   }
);

/* can be converted to extension, or whatever*/
var AlterPosition = function(oInput, oItst, nOffsetTop, nOffsetLeft)
{
   var divContainer = oInst.dpDiv;
   var oElem        = $(this);
       oInput       = $(oInput);

   setTimeout(function() 
   { 
      divContainer.css
      ({ 
         top  : (nOffsetTop >= 0 ? "+=" + nOffsetTop : "-=" + (nOffsetTop * -1)), 
         left : (nOffsetTop >= 0 ? "+=" + nOffsetLeft : "-=" + (nOffsetLeft * -1))
      }); 
   }, 10);
}
Brett Weber
  • 1,839
  • 18
  • 22
0

Within Jquery.UI, just update the _checkOffset function, so that viewHeight is added to offset.top, before offset is returned.

_checkOffset: function(inst, offset, isFixed) {
    var dpWidth = inst.dpDiv.outerWidth(),
    dpHeight = inst.dpDiv.outerHeight(),
    inputWidth = inst.input ? inst.input.outerWidth() : 0,
    inputHeight = inst.input ? inst.input.outerHeight() : 0,
    viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
            viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : ($(document).scrollTop()||document.body.scrollTop));
        offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
        offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
        offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? ($(document).scrollTop()||document.body.scrollTop) : 0;

        // now check if datepicker is showing outside window viewport - move to a better place if so.
        offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
            Math.abs(offset.left + dpWidth - viewWidth) : 0);
        offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
            Math.abs(dpHeight + inputHeight) : 0);
**offset.top = offset.top + viewHeight;**
        return offset;
    },
  • This solution is essentially correct: Inject your own _checkOffset() function via jQuery.extend() and return an arbitrary object having numeric properties "top" and "left", i.e. jQuery.extend( jQuery.datepicker, { _checkOffset: function (inst, offset, isFixed) { return { top: *mytop*, left: *myleft* };}}); where mytop and myleft is to your personal liking, for example derived from *inst*. – wh81752 Jul 16 '15 at 10:46
0
.ui-datepicker {-ms-transform: translate(100px,100px); -webkit-transform: translate(100px,100px); transform: translate(100px,100px);}
James
  • 21
  • 2
  • why the votedown? doesn't this address the issue? http://codepen.io/coconewty/pen/rajbNj – James Jan 12 '15 at 10:17
  • votedown? Because you were only reading the question's title and didn't take any effort to dig into the real problem. Simply assume that you have two datepicker attached to input fields with various widths. How does your solution ensure that each datepicker widget's left edge touches the inputs field right edge? On the other side, you should get at least one point for your answers originality. – wh81752 Jul 16 '15 at 10:52
0
$('.PDatePicker').MdPersianDateTimePicker({
                Placement: 'top',          
            });
hamed hossani
  • 986
  • 2
  • 14
  • 33
0

Here is another solution.

  1. Create function to fix the position

     function setDatepickerPos(input, inst) {
     var rect = input.getBoundingClientRect();
     // use 'setTimeout' to prevent effect overridden by other scripts
     setTimeout(function () {
         var scrollTop = $("body").scrollTop();
         inst.dpDiv.css({ top: rect.top + input.offsetHeight + scrollTop });
     }, 0);}
    
  2. Add the function to ‘beforeShow’ properties of datepicker

     $('#MyDatepicker').datepicker({
     dateFormat: "yy-mm-dd",
     changeMonth: true,
     changeYear: true,
     defaultDate: +0,
     inline: true,
     beforeShow: function (input, inst) { setDatepickerPos(input, inst) },});
    

Here is the reference link: link. All the credits should go to Aries.me

Thanooshan
  • 598
  • 12
  • 23
0

If your datepicker in the drag panel and panel has scrool. You must datepicker position calculate all scrool positon changes with interval.

$(function () {
    var datePickerInterval;

    $("#id").datepicker({
        beforeShow: function (input, inst) {
            var calendar = inst.dpDiv;
            datePickerInterval = setInterval(function () {
                calendar.position({
                    my: 'right top',
                    at: 'right bottom',
                    collision: 'none',
                    of: input
                });
            }, 10);
        },
        onClose: function () {
            clearInterval(datePickerInterval);
        }
    });
});
Ali BARUT
  • 1
  • 1