Tuesday, 9 September 2014

Styling the UI Bootstrap (AngularJS) Datepicker in SharePoint

I'm working on a SharePoint project at the moment using AngularJS to build a kind of SPA (Single Page Application).

There are a number of controls I need on the page, one them being a calendar / date picker. The client wanted the same experience as the SharePoint datepicker. I looked at several options for a datepicker control, and settled on using the datepicker directive included with the UI Bootstrap.

UI Bootstrap contains a number of directives for UI components, written in AngularJS by the AngularUI team, including a datepicker.

UI Bootstrap components can be downloaded here: UI Bootstrap

This datepicker works nicely, and it's a native AngularJS directive. However, the styling uses CSS classes from Bootstrap CSS. This isn't a bad thing; I like Bootstrap CSS a lot. But if I attach Bootstrap CSS to SharePoint without modification, the CSS will impact the styling of the SharePoint site.

My solution was to extract the styles used by the calendar control, slightly modify them to make the selectors more specific, and then add them to my solutions CSS file.

I modified the styles to:
* Remove the glyphicons and replace them with images or text (to make the control like more like the SharePoint calendar control).
* Added an additional selector to many of the CSS classes, to ensure the styles only targeted the datepicker.
* Make the datepicker slightly smaller (smaller buttons, fonts, etc). This made it a little more like the SharePoint OOTB calendar (only it's better!)

The end result looks like this:
When expanded, it looks like this:

I used the developer tools in Google Chrome to inspect the classes the datepicker uses, and then extract them out into a separate file. I then wrapped the datepicker in a parent DIV, to which I applied a CSS class to use to target the datepicker with new styles from Bootstrap.

The HTML markup for the control (I'm using the highlighted CSS class to enable me to specifically target the datepicker with the Bootstrap CSS):

<div class="ebcs-calendar">
    <p class="input-group ebcscontrol-long-calendar">
        <input type="text" class="form-control ebcscontrol-date-input" datepicker-popup="{{rec.calendar.format}}" name="Endorser1DueDate" ng-model="rec.item.eBriefEndorser1DueDate" is-open="rec.calendar.calendars['Endorser1DueDate']" min-date="rec.calendar.minDate" max-date="'2030-12-31'" datepicker-options="rec.calendar.dateOptions" ng-required="true" close-text="Close" />
        <span class="input-group-btn">
            <button type="button" class="btn btn-default ecbs-calendar-button" ng-click="rec.calendar.open($event, 'Endorser1DueDate')"><i class="glyphicon glyphicon-calendar"></i></button>

The CSS Styles (I've highlighted the CSS selector used to specifically target the datepicker with the Bootstrap CSS).

Note: You can download the cut-down version of the Bootstrap CSS I used here: http://gallery.technet.microsoft.com/Modified-for-using-the-69281fe6

<style type="text/css">
div.ebcs-calendar {
    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
    font-size: 14px;
    line-height: 1.42857143;
    color: #333;
    background-color: #fff;
div.ebcs-calendar button,
div.ebcs-calendar input,
div.ebcs-calendar optgroup,
div.ebcs-calendar select,
div.ebcs-calendar textarea {
    color: inherit;
    font: inherit;
    margin: 0;
div.ebcs-calendar input[type="button"],
div.ebcs-calendar input[type="submit"],
div.ebcs-calendar input[type="reset"],
div.ebcs-calendar > button {
    align-items: flex-start;
    text-align: center;
    cursor: default;
    color: buttontext;
    padding: 2px 6px 3px;
    border: 2px outset buttonface;
    border-image-source: initial;
    border-image-slice: initial;
    border-image-width: initial;
    border-image-outset: initial;
    border-image-repeat: initial;
    background-color: buttonface;
    box-sizing: border-box;

The snippet of styles below is where I've replaced the glyphicons with the default SharePoint calendar image, and some text for the backwards / forwards text.

<style type="text/css"
.glyphicon-calendar:before {
    content: " ";
    background-image: url('/_layouts/15/images/calendar_25.gif');
.glyphicon-chevron-left:before {
    content: "<";
    font-weight: 900;
    font-style: oblique;
.glyphicon-chevron-right:before {
    content: ">";
    font-weight: 900;
    font-style: oblique;
    background: url("/_layouts/15/images/calendar_25.gif") no-repeat scroll 0 0 transparent;
    border: 0;
    background: url("/_layouts/15/images/calendar_25.gif") no-repeat scroll 0 0 transparent;
    -webkit-box-shadow: none;
    box-shadow: none;