Highlight Days in JavaFX DatePicker

javafx

Today I had the requirement to implement a highlighting of some days in the JavaFX DatePicker. As I haven't found an existing blog post or tutorial that describes this topic I will provide a short example here.

Similar to other JavaFX controls like ListView or TreeTable the DatePicker can be configured with a CellFactory. In this cellFactory you can configure the styling of individual cells.

The basic code looks like this:

DatePicker datePicker = new DatePicker();

datePicker.setDayCellFactory(new Callback<DatePicker, DateCell>() {
  @Override
  public DateCell call(DatePicker param) {
    return new DateCell() {
      @Override
      public void updateItem(LocalDate item, boolean empty) {
        super.updateItem(item, empty);
      }
    }
  }
})

JavaFX will reuse existing DateCell instances when the visible viewport is changed when the user switches between pages in the DatePicker. This way JavaFX saves resources and minimizes new instances as much as possible.

To reuse existing cells we need to override the updateItem method which will get the new LocalDate object as parameter. Inside this method we can now check if this day should get a special styling.

In my example I will highlight the holidays (in Saxony, Germany) with a special color.

The first step is to define the list of LocalDates that we are interested in. Then we can check the given LocalDate value in the updateItem method.

List<LocalDate> holidays = new ArrayList<>();
holidays.add(LocalDate.of(2018, Month.JANUARY, 1));
holidays.add(LocalDate.of(2018, Month.MARCH, 3));
holidays.add(LocalDate.of(2018, Month.APRIL, 2));
holidays.add(LocalDate.of(2018, Month.MAY, 1));
holidays.add(LocalDate.of(2018, Month.MAY,10));
holidays.add(LocalDate.of(2018, Month.MAY,21));
holidays.add(LocalDate.of(2018, Month.OCTOBER,3));
holidays.add(LocalDate.of(2018, Month.OCTOBER,31));
holidays.add(LocalDate.of(2018, Month.NOVEMBER,21));
holidays.add(LocalDate.of(2018, Month.DECEMBER,25));
holidays.add(LocalDate.of(2018, Month.DECEMBER,26));


DatePicker datePicker = new DatePicker();

datePicker.setDayCellFactory(new Callback<DatePicker, DateCell>() {
	@Override
	public DateCell call(DatePicker param) {
		return new DateCell(){
			@Override
			public void updateItem(LocalDate item, boolean empty) {
				super.updateItem(item, empty);

				if (!empty && item != null) {
					if(holidays.contains(item)) {
						this.setStyle("-fx-background-color: pink");
					}
				}
			}
		};
	}
});

The result looks like this:

Screenshot

An even better approach is to use a CSS file to define the styling. In the cell-factory we then only set a CSS class that is referred to in the CSS file. The code of the cell-factory could look like this:

datePicker.setDayCellFactory(new Callback<DatePicker, DateCell>() {
	@Override
	public DateCell call(DatePicker param) {
		return new DateCell(){
			@Override
			public void updateItem(LocalDate item, boolean empty) {
				super.updateItem(item, empty);

				if (!empty && item != null) {
					if(holidays.contains(item)) {
						this.getStyleClass().add("holiday");
					}
				}
			}
		};
	}
});

To write the CSS code we can use the modena.css as a reference point. The code looks like this:

.date-picker-popup > * > .date-cell.holiday {
  -fx-background-color: pink;
}