title: Disable specific dates in Bootstrap Datepicker
body: <p>How can I disable specific days in the Bootstrap Datepicker? (<a href="http://www.eyecon.ro/bootstrap-datepicker/" rel="nofollow">Datepicker Homepage</a>)</p>
  
  <p>I am trying to provide an array of dates to the datepicker and have these specific dates (1) not be clickable and (2) have a different hover color.</p>
  
  <p>My specific usage is to only allow users to select dates that have an associated data file.</p>
  
  <p>Thanks!</p>
  
  <p>EDIT:</p>
  
  <p>This is the datepicker js code:</p>
  
  <pre><code>// Picker object
  
  var Datepicker = function(element, options){
      this.element = $(element);
      this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
      this.picker = $(DPGlobal.template)
                          .appendTo('body')
                          .on({
                              click: $.proxy(this.click, this),
                              mousedown: $.proxy(this.mousedown, this)
                          });
      this.isInput = this.element.is('input');
      this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
  
      if (this.isInput) {
          this.element.on({
              focus: $.proxy(this.show, this),
              blur: $.proxy(this.hide, this),
              keyup: $.proxy(this.update, this)
          });
      } else {
          if (this.component){
              this.component.on('click', $.proxy(this.show, this));
          } else {
              this.element.on('click', $.proxy(this.show, this));
          }
      }
  
      this.viewMode = 0;
      this.weekStart = options.weekStart||this.element.data('date-weekstart')||0;
      this.weekEnd = this.weekStart == 0 ? 6 : this.weekStart - 1;
      this.fillDow();
      this.fillMonths();
      this.update();
      this.showMode();
  };
  
  Datepicker.prototype = {
      constructor: Datepicker,
  
      show: function(e) {
          this.picker.show();
          this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
          this.place();
          $(window).on('resize', $.proxy(this.place, this));
          if (e ) {
              e.stopPropagation();
              e.preventDefault();
          }
          if (!this.isInput) {
              $(document).on('mousedown', $.proxy(this.hide, this));
          }
          this.element.trigger({
              type: 'show',
              date: this.date
          });
      },
  
      hide: function(){
          this.picker.hide();
          $(window).off('resize', this.place);
          this.viewMode = 0;
          this.showMode();
          if (!this.isInput) {
              $(document).off('mousedown', this.hide);
          }
          this.setValue();
          this.element.trigger({
              type: 'hide',
              date: this.date
          });
      },
  
      setValue: function() {
          var formated = DPGlobal.formatDate(this.date, this.format);
          if (!this.isInput) {
              if (this.component){
                  this.element.find('input').prop('value', formated);
              }
              this.element.data('date', formated);
          } else {
              this.element.prop('value', formated);
          }
      },
  
      place: function(){
          var offset = this.component ? this.component.offset() : this.element.offset();
          this.picker.css({
              top: offset.top + this.height,
              left: offset.left
          });
      },
  
      update: function(){
          this.date = DPGlobal.parseDate(
              this.isInput ? this.element.prop('value') : this.element.data('date'),
              this.format
          );
          this.viewDate = new Date(this.date);
          this.fill();
      },
  
      fillDow: function(){
          var dowCnt = this.weekStart;
          var html = '&lt;tr style="border-bottom: 1px solid #aeaeae; border-top: 1px solid #aeaeae;"&gt;';
          while (dowCnt &lt; this.weekStart + 7) {
              html += '&lt;th class="dow"&gt;'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'&lt;/th&gt;';
          }
          html += '&lt;/tr&gt;';
          this.picker.find('.datepicker-days thead').append(html);
      },
  
      fillMonths: function(){
          var html = '';
          var i = 0
          while (i &lt; 12) {
              html += '&lt;span class="month"&gt;'+DPGlobal.dates.monthsShort[i++]+'&lt;/span&gt;';
          }
          this.picker.find('.datepicker-months td').append(html);
      },
  
      fill: function() {
          var d = new Date(this.viewDate),
              year = d.getFullYear(),
              month = d.getMonth(),
              currentDate = this.date.valueOf();
          this.picker.find('.datepicker-days th:eq(1)')
                      .text(DPGlobal.dates.months[month]+' '+year);
          var prevMonth = new Date(year, month-1, 28,0,0,0,0),
              day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
          prevMonth.setDate(day);
          prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
          var nextMonth = new Date(prevMonth);
          nextMonth.setDate(nextMonth.getDate() + 42);
          nextMonth = nextMonth.valueOf();
          html = [];
          var clsName;
          while(prevMonth.valueOf() &lt; nextMonth) {
              if (prevMonth.getDay() == this.weekStart) {
                  html.push('&lt;tr&gt;');
              }
              clsName = '';
              if (prevMonth.getMonth() &lt; month) {
                  clsName += ' old';
              } else if (prevMonth.getMonth() &gt; month) {
                  clsName += ' new';
              }
              if (prevMonth.valueOf() == currentDate) {
                  clsName += ' active';
              }
              html.push('&lt;td class="day'+clsName+'" style="border: 0px;"&gt;'+prevMonth.getDate() + '&lt;/td&gt;');
              if (prevMonth.getDay() == this.weekEnd) {
                  html.push('&lt;/tr&gt;');
              }
              prevMonth.setDate(prevMonth.getDate()+1);
          }
          this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
          var currentYear = this.date.getFullYear();
  
          var months = this.picker.find('.datepicker-months')
                      .find('th:eq(1)')
                          .text(year)
                          .end()
                      .find('span').removeClass('active');
          if (currentYear == year) {
              months.eq(this.date.getMonth()).addClass('active');
          }
  
          html = '';
          year = parseInt(year/10, 10) * 10;
          var yearCont = this.picker.find('.datepicker-years')
                              .find('th:eq(1)')
                                  .text(year + '-' + (year + 9))
                                  .end()
                              .find('td');
          year -= 1;
          for (var i = -1; i &lt; 11; i++) {
              html += '&lt;span class="year'+(i == -1 || i == 10 ? ' old' : '')+(currentYear == year ? ' active' : '')+'"&gt;'+year+'&lt;/span&gt;';
              year += 1;
          }
          yearCont.html(html);
      },
  
      click: function(e) {
          e.stopPropagation();
          e.preventDefault();
          var target = $(e.target).closest('span, td, th');
          if (target.length == 1) {
              switch(target[0].nodeName.toLowerCase()) {
                  case 'th':
                      switch(target[0].className) {
                          case 'switch':
                              this.showMode(1);
                              break;
                          case 'prev':
                          case 'next':
                              this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call(
                                  this.viewDate,
                                  this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + 
                                  DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1)
                              );
                              this.fill();
                              break;
                      }
                      break;
                  case 'span':
                      if (target.is('.month')) {
                          var month = target.parent().find('span').index(target);
                          this.viewDate.setMonth(month);
                      } else {
                          var year = parseInt(target.text(), 10)||0;
                          this.viewDate.setFullYear(year);
                      }
                      this.showMode(-1);
                      this.fill();
                      break;
                  case 'td':
                      if (target.is('.day')){
                          var day = parseInt(target.text(), 10)||1;
                          var month = this.viewDate.getMonth();
                          if (target.is('.old')) {
                              month -= 1;
                          } else if (target.is('.new')) {
                              month += 1;
                          }
                          var year = this.viewDate.getFullYear();
                          this.date = new Date(year, month, day,0,0,0,0);
                          this.viewDate = new Date(year, month, day,0,0,0,0);
                          this.fill();
                          this.setValue();
                          this.element.trigger({
                              type: 'changeDate',
                              date: this.date
                          });
                      }
                      break;
              }
          }
      },
  
      mousedown: function(e){
          e.stopPropagation();
          e.preventDefault();
      },
  
      showMode: function(dir) {
          if (dir) {
              this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
          }
          this.picker.find('&gt;div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
      }
  };
  
  $.fn.datepicker = function ( option ) {
      return this.each(function () {
          var $this = $(this),
              data = $this.data('datepicker'),
              options = typeof option == 'object' &amp;&amp; option;
          if (!data) {
              $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
          }
          if (typeof option == 'string') data[option]();
      });
  };
  
  $.fn.datepicker.defaults = {
  };
  $.fn.datepicker.Constructor = Datepicker;
  
  var DPGlobal = {
      modes: [
          {
              clsName: 'days',
              navFnc: 'Month',
              navStep: 1
          },
          {
              clsName: 'months',
              navFnc: 'FullYear',
              navStep: 1
          },
          {
              clsName: 'years',
              navFnc: 'FullYear',
              navStep: 10
      }],
      dates:{
          days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
          daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
          daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
          months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
          monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
      },
      isLeapYear: function (year) {
          return (((year % 4 === 0) &amp;&amp; (year % 100 !== 0)) || (year % 400 === 0))
      },
      getDaysInMonth: function (year, month) {
          return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
      },
      parseFormat: function(format){
          var separator = format.match(/[.\/-].*?/),
              parts = format.split(/\W+/);
          if (!separator || !parts || parts.length == 0){
              throw new Error("Invalid date format.");
          }
          return {separator: separator, parts: parts};
      },
      parseDate: function(date, format) {
          var parts = date.split(format.separator),
              date = new Date(1970, 1, 1, 0, 0, 0),
              val;
          if (parts.length == format.parts.length) {
              for (var i=0, cnt = format.parts.length; i &lt; cnt; i++) {
                  val = parseInt(parts[i], 10)||1;
                  switch(format.parts[i]) {
                      case 'dd':
                      case 'd':
                          date.setDate(val);
                          break;
                      case 'mm':
                      case 'm':
                          date.setMonth(val - 1);
                          break;
                      case 'yy':
                          date.setFullYear(2000 + val);
                          break;
                      case 'yyyy':
                          date.setFullYear(val);
                          break;
                  }
              }
          }
          return date;
      },
      formatDate: function(date, format){
          var val = {
              d: date.getDate(),
              m: date.getMonth() + 1,
              yy: date.getFullYear().toString().substring(2),
              yyyy: date.getFullYear()
          };
          val.dd = (val.d &lt; 10 ? '0' : '') + val.d;
          val.mm = (val.m &lt; 10 ? '0' : '') + val.m;
          var date = [];
          for (var i=0, cnt = format.parts.length; i &lt; cnt; i++) {
              date.push(val[format.parts[i]]);
          }
          return date.join(format.separator);
      },
      headTemplate: '&lt;thead&gt;'+
                          '&lt;tr&gt;'+
                              '&lt;th class="prev"&gt;&lt;i class="icon-arrow-left"/&gt;&lt;/th&gt;'+
                              '&lt;th colspan="5" class="switch"&gt;&lt;/th&gt;'+
                              '&lt;th class="next"&gt;&lt;i class="icon-arrow-right"/&gt;&lt;/th&gt;'+
                          '&lt;/tr&gt;'+
                      '&lt;/thead&gt;',
      contTemplate: '&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="7" style="border: 0px;"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;'
  };
  DPGlobal.template = '&lt;div class="datepicker dropdown-menu"&gt;'+
                          '&lt;div class="datepicker-days"&gt;'+
                              '&lt;table class=" table-condensed" style="border: 0px;"&gt;'+
                                  DPGlobal.headTemplate+
                                  '&lt;tbody&gt;&lt;/tbody&gt;'+
                              '&lt;/table&gt;'+
                          '&lt;/div&gt;'+
                          '&lt;div class="datepicker-months"&gt;'+
                              '&lt;table class="table-condensed" style="border: 0px;"&gt;'+
                                  DPGlobal.headTemplate+
                                  DPGlobal.contTemplate+
                              '&lt;/table&gt;'+
                          '&lt;/div&gt;'+
                          '&lt;div class="datepicker-years"&gt;'+
                              '&lt;table class="table-condensed" style="border: 0px;"&gt;'+
                                  DPGlobal.headTemplate+
                                  DPGlobal.contTemplate+
                              '&lt;/table&gt;'+
                          '&lt;/div&gt;'+
                      '&lt;/div&gt;';
  </code></pre>