You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2021/10/15 19:32:00 UTC

[myfaces-tobago] branch tobago-5.x updated: feat: Replace date-picker implementation with browser impl

This is an automated email from the ASF dual-hosted git repository.

lofwyr pushed a commit to branch tobago-5.x
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git


The following commit(s) were added to refs/heads/tobago-5.x by this push:
     new 426eb50  feat: Replace date-picker implementation with browser impl
426eb50 is described below

commit 426eb50ad37f238fef0ccad893f6c455665baec8
Author: Udo Schnurpfeil <ud...@irian.eu>
AuthorDate: Fri Oct 15 21:24:29 2021 +0200

    feat: Replace date-picker implementation with browser impl
    
    issues: TOBAGO-2036
---
 .../myfaces/tobago/convert/DateTimeConverter.java  |  180 --
 .../tobago/facelets/ConvertDateTimeHandler.java    |  127 -
 .../tobago/internal/component/AbstractUIDate.java  |    8 +-
 .../tobago/internal/context/DateTimeI18n.java      |  145 --
 .../internal/renderkit/renderer/DateRenderer.java  |  122 +-
 .../component/ConvertDateTimeTagDeclaration.java   |   85 -
 .../taglib/component/DateTagDeclaration.java       |   75 +-
 .../myfaces/tobago/internal/util/JsonUtils.java    |   26 -
 .../org/apache/myfaces/tobago/model/DateModel.java |   78 -
 .../org/apache/myfaces/tobago/model/DateType.java  |  100 +
 .../DateTypeEditor.java}                           |   17 +-
 .../renderkit/renderer/DateRendererUnitTest.java   |   19 +
 .../tobago/internal/util/JsonUtilsUnitTest.java    |   23 -
 .../src/test/resources/renderer/date/dateAuto.html |    2 +-
 .../src/test/resources/renderer/date/dateBoth.html |    2 +-
 .../src/test/resources/renderer/date/dateDate.html |    2 +-
 .../src/test/resources/renderer/date/dateTime.html |    2 +-
 .../test/resources/renderer/date/dateTimeStep.html |   19 +-
 .../resources/renderer/date/localDateAuto.html     |    2 +-
 .../resources/renderer/date/localDateTimeAuto.html |    4 +-
 .../resources/renderer/date/localTimeAuto.html     |    4 +-
 .../src/test/resources/renderer/date/minMax.html   |    2 +-
 .../test/resources/renderer/date/testLabel.html    |    2 +-
 .../resources/renderer/date/testTodayButton.html   |    2 +-
 .../src/test/resources/renderer/date/text.html     |    2 +-
 .../resources/renderer/date/zonedDateTimeAuto.html |    4 +-
 .../example/demo/ConvertDateTimeController.java    |  172 --
 .../example/demo/CurrentValueController.java       |   32 +-
 .../tobago/example/demo/DateTestController.java    |  122 +
 .../tobago/example/demo/SheetController.java       |   31 -
 .../50-migration/95-migration/4.0_to_5.0.xhtml     |    9 +
 .../webapp/content/010-input/40-date/Date.xhtml    |    7 +-
 .../080-sheet/80-editable/Sheet_Editable.xhtml     |    2 +-
 .../Date_TobagoConverter.test.js                   |  241 --
 .../Date_TobagoConverter.xhtml                     |  235 --
 .../webapp/content/900-test/1100-date/Date.xhtml   |  134 +
 .../3000-sheet/10-sheet-types/Sheet_Types.xhtml    |    5 +-
 .../RendererBase_GetCurrentValue.xhtml             |    4 +-
 tobago-theme/package-lock.json                     |    5 -
 tobago-theme/package.json                          |    3 +-
 tobago-theme/src/main/scss/datepicker-bs5.scss     |  116 -
 .../src/main/css/tobago.css                        |  251 --
 .../src/main/css/tobago.css.map                    |    2 +-
 .../src/main/css/tobago.min.css                    |    2 +-
 .../src/main/css/tobago.min.css.map                |    2 +-
 .../src/main/scss/tobago-theme.scss                |    5 -
 .../src/main/css/tobago.css                        |  251 --
 .../src/main/css/tobago.css.map                    |    2 +-
 .../src/main/css/tobago.min.css                    |    2 +-
 .../src/main/css/tobago.min.css.map                |    2 +-
 .../src/main/scss/tobago-theme.scss                |    5 -
 .../src/main/css/tobago.css                        |  251 --
 .../src/main/css/tobago.css.map                    |    2 +-
 .../src/main/css/tobago.min.css                    |    2 +-
 .../src/main/css/tobago.min.css.map                |    2 +-
 .../src/main/scss/tobago-theme.scss                |    5 -
 .../tobago-theme-speyside/src/main/css/tobago.css  |  251 --
 .../src/main/css/tobago.css.map                    |    2 +-
 .../src/main/css/tobago.min.css                    |    2 +-
 .../src/main/css/tobago.min.css.map                |    2 +-
 .../src/main/scss/tobago-theme.scss                |    5 -
 .../tobago-theme-standard/src/main/css/tobago.css  |  251 --
 .../src/main/css/tobago.css.map                    |    2 +-
 .../src/main/css/tobago.min.css                    |    2 +-
 .../src/main/css/tobago.min.css.map                |    2 +-
 .../tobago-theme-standard/src/main/js/tobago.js    | 2692 +-------------------
 .../src/main/js/tobago.js.map                      |    2 +-
 .../src/main/js/tobago.min.js                      |    4 +-
 .../src/main/js/tobago.min.js.map                  |    2 +-
 .../src/main/scss/tobago-theme.scss                |    5 -
 .../src/main/ts/tobago-date.ts                     |  189 +-
 .../org/apache/myfaces/tobago/apt/component.stg    |    2 +-
 72 files changed, 713 insertions(+), 5660 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/convert/DateTimeConverter.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/convert/DateTimeConverter.java
deleted file mode 100644
index b19ffe3..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/convert/DateTimeConverter.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.convert;
-
-import org.apache.myfaces.tobago.internal.util.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIInput;
-import javax.faces.context.FacesContext;
-import javax.faces.convert.ConverterException;
-import java.lang.invoke.MethodHandles;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.TemporalAccessor;
-import java.util.Calendar;
-import java.util.Locale;
-import java.util.TimeZone;
-
-import static org.apache.myfaces.tobago.convert.DateTimeConverter.CONVERTER_ID;
-
-/**
- * @deprecated Since 5.0.0. Should work with &lt;f:convertDateTime%gt; since JSF 2.3.
- */
-@Deprecated
-@org.apache.myfaces.tobago.apt.annotation.Converter(id = CONVERTER_ID)
-public class DateTimeConverter extends javax.faces.convert.DateTimeConverter {
-
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  public static final String CONVERTER_ID = "org.apache.myfaces.tobago.DateTime";
-
-  private static final String TYPE_DATE = "date";
-  private static final String TYPE_TIME = "time";
-  private static final String TYPE_BOTH = "both";
-  private static final String TYPE_CALENDAR = "calendar";
-  private static final String TYPE_LOCAL_DATE = "localDate";
-  private static final String TYPE_LOCAL_TIME = "localTime";
-  private static final String TYPE_LOCAL_DATE_TIME = "localDateTime";
-  private static final String TYPE_OFFSET_TIME = "offsetTime";
-  private static final String TYPE_OFFSET_DATE_TIME = "offsetDateTime";
-  private static final String TYPE_ZONED_DATE_TIME = "zonedDateTime";
-
-  @Override
-  public Object getAsObject(FacesContext facesContext, UIComponent component, String string) throws ConverterException {
-    if (StringUtils.isBlank(string)) {
-      return null;
-    } else {
-      final String type = getType();
-      if (TYPE_DATE.equals(type) || TYPE_TIME.equals(type) || TYPE_BOTH.equals(type)) {
-        return super.getAsObject(facesContext, component, string);
-      } else if (TYPE_CALENDAR.equals(type)) {
-        final Locale locale = getLocale();
-        final String pattern = getPattern();
-        final TimeZone timeZone = getTimeZone();
-        final Calendar calendar;
-        if (component instanceof UIInput && ((UIInput) component).getValue() != null) {
-          calendar = (Calendar) ((UIInput) component).getValue();
-        } else {
-          if (timeZone != null && locale != null) {
-            calendar = Calendar.getInstance(timeZone, locale);
-          } else if (locale != null) {
-            calendar = Calendar.getInstance(locale);
-          } else if (timeZone != null) {
-            calendar = Calendar.getInstance(timeZone);
-          } else {
-            calendar = Calendar.getInstance();
-          }
-        }
-
-        SimpleDateFormat sdf = locale != null ? new SimpleDateFormat(pattern, locale) : new SimpleDateFormat(pattern);
-        try {
-          calendar.setTime(sdf.parse(string));
-        } catch (ParseException e) {
-          throw new ConverterException("string='" + string + "'", e);
-        }
-
-        return calendar;
-      } else if (TYPE_LOCAL_DATE.equals(type)) {
-        logMandatoryPatterns("yMd");
-        return getDateTimeFormatter().parse(string, LocalDate::from);
-      } else if (TYPE_LOCAL_TIME.equals(type)) {
-        logMandatoryPatterns("H");
-        return getDateTimeFormatter().parse(string, LocalTime::from);
-      } else if (TYPE_LOCAL_DATE_TIME.equals(type)) {
-        logMandatoryPatterns("yMdH");
-        return getDateTimeFormatter().parse(string, LocalDateTime::from);
-      } else if (TYPE_OFFSET_TIME.equals(type)) {
-        logMandatoryPatterns("HZ");
-        return getDateTimeFormatter().parse(string, OffsetTime::from);
-      } else if (TYPE_OFFSET_DATE_TIME.equals(type)) {
-        logMandatoryPatterns("yMdHZ");
-        return getDateTimeFormatter().parse(string, OffsetDateTime::from);
-      } else if (TYPE_ZONED_DATE_TIME.equals(type)) {
-        logMandatoryPatterns("yMdHZ");
-        return getDateTimeFormatter().parse(string, ZonedDateTime::from);
-      } else {
-        throw new ConverterException("invalid type '" + type + "'");
-      }
-    }
-  }
-
-  @Override
-  public String getAsString(FacesContext facesContext, UIComponent component, Object object) throws ConverterException {
-    if (object == null) {
-      return null;
-    } else {
-      final String type = getType();
-      if (TYPE_DATE.equals(type) || TYPE_TIME.equals(type) || TYPE_BOTH.equals(type)) {
-        return super.getAsString(facesContext, component, object);
-      } else if (TYPE_CALENDAR.equals(type)) {
-        Calendar calendar = (Calendar) object;
-        final Locale locale = getLocale();
-        final String pattern = getPattern();
-
-        SimpleDateFormat sdf = new SimpleDateFormat(pattern, locale);
-        return sdf.format(calendar.getTime());
-      } else if (TYPE_LOCAL_DATE.equals(type)
-          || TYPE_LOCAL_TIME.equals(type)
-          || TYPE_LOCAL_DATE_TIME.equals(type)
-          || TYPE_OFFSET_TIME.equals(type)
-          || TYPE_OFFSET_DATE_TIME.equals(type)
-          || TYPE_ZONED_DATE_TIME.equals(type)) {
-        return getDateTimeFormatter().format((TemporalAccessor) object);
-      } else {
-        throw new ConverterException("invalid type '" + type + "'");
-      }
-    }
-  }
-
-  private void logMandatoryPatterns(String mandatoryChars) {
-    logMandatoryPattern(mandatoryChars, "y", "year");
-    logMandatoryPattern(mandatoryChars, "M", "month");
-    logMandatoryPattern(mandatoryChars, "d", "day");
-    logMandatoryPattern(mandatoryChars, "H", "hour");
-    logMandatoryPattern(mandatoryChars, "Z", "offset");
-  }
-
-  private void logMandatoryPattern(String mandatoryChars, String c, String name) {
-    final String pattern = getPattern();
-    if (pattern != null && mandatoryChars.contains(c) && !pattern.contains(c)) {
-      LOG.error("No char for " + name + " ('" + c + "') in pattern: " + pattern);
-    }
-  }
-
-  private DateTimeFormatter getDateTimeFormatter() {
-    final String pattern = getPattern();
-    if (!StringUtils.isBlank(pattern)) {
-      final Locale locale = getLocale();
-      return locale != null ? DateTimeFormatter.ofPattern(pattern, locale) : DateTimeFormatter.ofPattern(pattern);
-    } else {
-      throw new ConverterException("no pattern set");
-    }
-  }
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/ConvertDateTimeHandler.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/ConvertDateTimeHandler.java
deleted file mode 100644
index 98cbd7a..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/ConvertDateTimeHandler.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.facelets;
-
-import org.apache.myfaces.tobago.convert.DateTimeConverter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.el.ELException;
-import javax.el.ValueExpression;
-import javax.faces.component.UIComponent;
-import javax.faces.component.ValueHolder;
-import javax.faces.context.FacesContext;
-import javax.faces.convert.Converter;
-import javax.faces.view.facelets.ComponentHandler;
-import javax.faces.view.facelets.ConverterConfig;
-import javax.faces.view.facelets.ConverterHandler;
-import javax.faces.view.facelets.FaceletContext;
-import javax.faces.view.facelets.TagAttribute;
-import javax.faces.view.facelets.TagException;
-import java.lang.invoke.MethodHandles;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * @deprecated Since 5.0.0. Should work with &lt;f:convertDateTime%gt; since JSF 2.3.
- */
-@Deprecated
-public class ConvertDateTimeHandler extends ConverterHandler {
-
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  private final TagAttribute binding;
-  private final TagAttribute locale;
-  private final TagAttribute pattern;
-  private final TagAttribute timeZone;
-  private final TagAttribute type;
-
-  public ConvertDateTimeHandler(final ConverterConfig config) {
-    super(config);
-    binding = getAttribute("binding");
-    locale = getAttribute("locale");
-    pattern = getAttribute("pattern");
-    timeZone = getAttribute("timeZone");
-    type = getAttribute("type");
-  }
-
-  @Override
-  public void apply(final FaceletContext faceletContext, final UIComponent parent) throws ELException {
-    if (parent instanceof ValueHolder) {
-      if (ComponentHandler.isNew(parent)) {
-        final ValueHolder valueHolder = (ValueHolder) parent;
-        Converter converter = null;
-        ValueExpression valueExpression = null;
-        if (binding != null) {
-          valueExpression = binding.getValueExpression(faceletContext, Converter.class);
-          converter = (Converter) valueExpression.getValue(faceletContext);
-        }
-        if (converter == null) {
-          converter = FacesContext.getCurrentInstance().getApplication()
-              .createConverter(DateTimeConverter.CONVERTER_ID);
-          DateTimeConverter dtConverter = (DateTimeConverter) converter;
-
-          if (locale != null) {
-            final Object localeObject = locale.getObject(faceletContext);
-            if (localeObject instanceof Locale) {
-              dtConverter.setLocale((Locale) localeObject);
-            } else {
-              LOG.warn("Could not set local.");
-            }
-          }
-          if (pattern != null) {
-            final Object patternObject = pattern.getObject(faceletContext);
-            if (patternObject instanceof String) {
-              dtConverter.setPattern((String) patternObject);
-            } else {
-              LOG.warn("Could not set pattern.");
-            }
-          }
-          if (timeZone != null) {
-            final Object timeZoneObject = timeZone.getObject(faceletContext);
-            if (timeZoneObject instanceof TimeZone) {
-              dtConverter.setTimeZone((TimeZone) timeZoneObject);
-            } else {
-              LOG.warn("Could not set time zone.");
-            }
-          }
-          if (type != null) {
-            final Object typeObject = type.getObject(faceletContext);
-            if (typeObject instanceof String) {
-              dtConverter.setType((String) typeObject);
-            } else {
-              LOG.warn("Could not set type.");
-            }
-          }
-
-          if (valueExpression != null) {
-            valueExpression.setValue(faceletContext, converter);
-          }
-        }
-        if (converter != null) {
-          valueHolder.setConverter(converter);
-        }
-        // TODO else LOG.warn?
-      }
-    } else {
-      throw new TagException(tag, "Parent is not of type ValueHolder, type is: " + parent);
-    }
-  }
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIDate.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIDate.java
index 470d96e..0167246 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIDate.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIDate.java
@@ -19,7 +19,7 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
-import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
+import org.apache.myfaces.tobago.model.DateType;
 
 /**
  * {@link org.apache.myfaces.tobago.internal.taglib.component.DateTagDeclaration}
@@ -38,11 +38,13 @@ public abstract class AbstractUIDate extends AbstractUIInput {
 
   public abstract boolean isTodayButton();
 
-  public abstract HtmlInputTypes getType();
+  public abstract DateType getType();
 
-  public abstract void setType(HtmlInputTypes type);
+  public abstract void setType(DateType type);
 
   public abstract Object getMin();
 
   public abstract Object getMax();
+
+  public abstract Double getStep();
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/context/DateTimeI18n.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/context/DateTimeI18n.java
deleted file mode 100644
index fda2aeb..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/context/DateTimeI18n.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.internal.context;
-
-import org.apache.myfaces.tobago.util.ResourceUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.faces.context.FacesContext;
-import java.lang.invoke.MethodHandles;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-public class DateTimeI18n {
-
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  private static final Map<Locale, DateTimeI18n> CACHE = new HashMap<>();
-
-  private final String[] days = new String[7];
-  private final String[] daysShort = new String[7];
-  private final String[] daysMin = new String[7];
-  private final String[] months = new String[12];
-  private final String[] monthsShort = new String[12];
-  private final String today;
-//  private final String monthTitle;
-  private final String clear;
-  private final int weekStart;
-//  private final String format;
-//  private final String titleFormat;
-
-  private final int minDays; // XXX why?
-  private final String cancel; // XXX why?
-  private final String week; // XXX why?
-
-  private DateTimeI18n(final Locale locale) {
-
-    LOG.debug("Creating DateTimeI18n for locale: " + locale);
-
-    final Calendar calendar = Calendar.getInstance(locale);
-
-    calendar.set(2000, Calendar.JANUARY, 1);
-    final SimpleDateFormat dateFormatMMMMM = new SimpleDateFormat("MMMMM", locale);
-    final SimpleDateFormat dateFormatMMM = new SimpleDateFormat("MMM", locale);
-    for (int i = 0; i < months.length; i++) {
-      months[i] = dateFormatMMMMM.format(calendar.getTime());
-      monthsShort[i] = dateFormatMMM.format(calendar.getTime());
-      calendar.add(Calendar.MONTH, 1);
-    }
-
-    final SimpleDateFormat dateFormatEEEEE = new SimpleDateFormat("EEEEE", locale);
-    final SimpleDateFormat dateFormatEEE = new SimpleDateFormat("EEE", locale);
-    final SimpleDateFormat dateFormatE = new SimpleDateFormat("E", locale);
-    calendar.set(2000, Calendar.JANUARY, 2);
-    for (int i = 0; i < days.length; i++) {
-      days[i] = dateFormatEEEEE.format(calendar.getTime());
-      daysShort[i] = dateFormatEEE.format(calendar.getTime());
-      daysMin[i] = dateFormatE.format(calendar.getTime());
-      calendar.add(Calendar.DAY_OF_YEAR, 1);
-    }
-
-    weekStart = calendar.getFirstDayOfWeek() - 1; // because Java: 1 = Sunday and JavaScript: 0 = Sunday
-    minDays = calendar.getMinimalDaysInFirstWeek();
-
-    FacesContext facesContext = FacesContext.getCurrentInstance();
-    today = ResourceUtils.getString(facesContext, "date.today");
-    cancel = ResourceUtils.getString(facesContext, "date.cancel");
-    clear = ResourceUtils.getString(facesContext, "date.clear");
-    week = ResourceUtils.getString(facesContext, "date.week");
-  }
-
-  public static synchronized DateTimeI18n valueOf(final Locale locale) {
-    DateTimeI18n dateTimeI18n;
-    dateTimeI18n = CACHE.get(locale);
-    if (dateTimeI18n == null) {
-      dateTimeI18n = new DateTimeI18n(locale);
-      CACHE.put(locale, dateTimeI18n);
-    }
-    return dateTimeI18n;
-  }
-
-  public String[] getMonths() {
-    return months;
-  }
-
-  public String[] getMonthsShort() {
-    return monthsShort;
-  }
-
-  public String[] getDays() {
-    return days;
-  }
-
-  public String[] getDaysShort() {
-    return daysShort;
-  }
-
-  public String[] getDaysMin() {
-    return daysMin;
-  }
-
-  public int getWeekStart() {
-    return weekStart;
-  }
-
-  public int getMinDays() {
-    return minDays;
-  }
-
-  public String getToday() {
-    return today;
-  }
-
-  public String getCancel() {
-    return cancel;
-  }
-
-  public String getClear() {
-    return clear;
-  }
-
-  public String getWeek() {
-    return week;
-  }
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
index c174d2a..f66d6fc 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRenderer.java
@@ -21,10 +21,9 @@ package org.apache.myfaces.tobago.internal.renderkit.renderer;
 
 import org.apache.myfaces.tobago.component.Attributes;
 import org.apache.myfaces.tobago.internal.component.AbstractUIDate;
-import org.apache.myfaces.tobago.internal.context.DateTimeI18n;
 import org.apache.myfaces.tobago.internal.util.AccessKeyLogger;
 import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
-import org.apache.myfaces.tobago.internal.util.JsonUtils;
+import org.apache.myfaces.tobago.model.DateType;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.Icons;
 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
@@ -32,7 +31,6 @@ import org.apache.myfaces.tobago.renderkit.html.CustomAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlButtonTypes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
-import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 import org.apache.myfaces.tobago.util.ResourceUtils;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
@@ -50,7 +48,6 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.Calendar;
 import java.util.Date;
 
 public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendererBase<T> {
@@ -69,12 +66,6 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
   private static final String TYPE_MONTH = "month";
   private static final String TYPE_WEEK = "week";
 
-  private static final String PATTERN_DATE = "yyyy-MM-dd";
-  private static final String PATTERN_DATETIME = "yyyy-MM-dd'T'HH:mm:ss.SSS";
-  private static final String PATTERN_TIME = "HH:mm:ss.SSS";
-  private static final String PATTERN_MONTH = "yyyy-MM";
-  private static final String PATTERN_WEEK = "yyyy-'W'MM";
-
   @Override
   public void encodeBeginInternal(FacesContext facesContext, T component) throws IOException {
     prepare(facesContext, component);
@@ -97,9 +88,7 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
       throws IOException {
 
     super.writeAdditionalAttributes(facesContext, writer, date);
-//    writer.writeAttribute(HtmlAttributes.PATTERN,
-    final DateTimeI18n dateTimeI18n = DateTimeI18n.valueOf(facesContext.getViewRoot().getLocale());
-    writer.writeAttribute(CustomAttributes.I18N, JsonUtils.encode(dateTimeI18n), true);
+//    writer.writeAttribute(HtmlAttributes.PATTERN, date.getPattern(), true);
     writer.writeAttribute(CustomAttributes.TODAY_BUTTON, date.isTodayButton());
   }
 
@@ -114,7 +103,7 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
     writer.writeClassAttribute(BootstrapClass.INPUT_GROUP);
 
     final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
-    final HtmlInputTypes type = component.getType();
+    final DateType type = component.getType();
 
     final String currentValue = getCurrentValue(facesContext, component);
     final String clientId = component.getClientId(facesContext);
@@ -130,7 +119,11 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
       AccessKeyLogger.addAccessKey(facesContext, component.getAccessKey(), clientId);
     }
 
-    writer.writeAttribute(HtmlAttributes.TYPE, type.getValue(), false);
+    writer.writeAttribute(HtmlAttributes.TYPE, type.getName(), false);
+    final Double step = component.getStep();
+    if (step != null) {
+      writer.writeAttribute(HtmlAttributes.STEP, Double.toString(step), false);
+    }
     writer.writeNameAttribute(clientId);
     writer.writeIdAttribute(fieldId);
     HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
@@ -234,40 +227,51 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
         LOG.warn("No converter for java.lang.String");
         return null;
       } else {
-        final DateTimeConverter dateTimeConverter
-            = (DateTimeConverter) facesContext.getApplication().createConverter("javax.faces.DateTime");
+        final DateTimeConverter dateTimeConverter = (DateTimeConverter)
+            facesContext.getApplication().createConverter("javax.faces.DateTime");
         if (estimatedType.isAssignableFrom(LocalDateTime.class)) {
           dateTimeConverter.setType("localDateTime");
-          dateTimeConverter.setPattern(PATTERN_DATETIME);
+          final Double step = component.getStep();
+          if (step == null || step >= 60) {
+            dateTimeConverter.setPattern(DateType.PATTERN_DATETIME_LOCAL);
+          } else if (step >= 1) {
+            dateTimeConverter.setPattern(DateType.PATTERN_DATETIME_LOCAL_SECONDS);
+          } else {
+            dateTimeConverter.setPattern(DateType.PATTERN_DATETIME_LOCAL_MILLIS);
+          }
         } else if (estimatedType.isAssignableFrom(LocalDate.class)) {
           dateTimeConverter.setType("localDate");
-          dateTimeConverter.setPattern(PATTERN_DATE);
+          dateTimeConverter.setPattern(DateType.PATTERN_DATE);
         } else if (estimatedType.isAssignableFrom(LocalTime.class)) {
           dateTimeConverter.setType("localTime");
-          dateTimeConverter.setPattern(PATTERN_TIME);
+          final Double step = component.getStep();
+          if (step == null || step >= 60) {
+            dateTimeConverter.setPattern(DateType.PATTERN_TIME);
+          } else if (step >= 1) {
+            dateTimeConverter.setPattern(DateType.PATTERN_TIME_SECONDS);
+          } else {
+            dateTimeConverter.setPattern(DateType.PATTERN_TIME_MILLIS);
+          }
         } else if (estimatedType.isAssignableFrom(ZonedDateTime.class)) {
           dateTimeConverter.setType("zonedDateTime");
-          dateTimeConverter.setPattern(PATTERN_DATETIME);
+          final Double step = component.getStep();
+          if (step == null || step >= 60) {
+            dateTimeConverter.setPattern(DateType.PATTERN_DATETIME_LOCAL);
+          } else if (step >= 1) {
+            dateTimeConverter.setPattern(DateType.PATTERN_DATETIME_LOCAL_SECONDS);
+          } else {
+            dateTimeConverter.setPattern(DateType.PATTERN_DATETIME_LOCAL_MILLIS);
+          }
         } else if (estimatedType.isAssignableFrom(Long.class)) {
           dateTimeConverter.setType("date");
-          dateTimeConverter.setPattern(PATTERN_DATE);
+          dateTimeConverter.setPattern(DateType.PATTERN_DATE);
         } else if (estimatedType.isAssignableFrom(Date.class)) {
           dateTimeConverter.setType("date");
-          dateTimeConverter.setPattern(PATTERN_DATE);
-        } else if (estimatedType.isAssignableFrom(Calendar.class)) {
-          dateTimeConverter.setType("date");
-          dateTimeConverter.setPattern(PATTERN_DATE);
+          dateTimeConverter.setPattern(DateType.PATTERN_DATE);
         } else if (estimatedType.isAssignableFrom(Number.class)) {
           LOG.error("date");
           dateTimeConverter.setType("date");
-          dateTimeConverter.setPattern(PATTERN_DATE);
-//      } else if (estimatedType.isAssignableFrom(Month.class)) {
-//        LOG.error("month");
-//        dateTimeConverter.setType("month"); // XXX is there a type month?
-//      } else if (estimatedType.isAssignableFrom(Week.class)) {
-//        LOG.error("week");
-//        dateTimeConverter.setType("week"); // XXX is there a type week?
-          // todo: ZonedDateTime
+          dateTimeConverter.setPattern(DateType.PATTERN_DATE);
         } else {
           LOG.warn("Type might not be supported (type='{}' clientId='{}')!",
               estimatedType.getName(), component.getClientId(facesContext));
@@ -308,7 +312,7 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
   }
 
   private void prepare(final FacesContext facesContext, final T component) {
-    HtmlInputTypes type = component.getType();
+    DateType type = component.getType();
     String pattern = component.getPattern();
 
     DateTimeConverter converter = null;
@@ -323,32 +327,32 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
       if (converter != null) {
         final String typeFromConverter = converter.getType();
         if (TYPE_DATE.equals(typeFromConverter)) {
-          type = HtmlInputTypes.DATE;
+          type = DateType.DATE;
         } else if (TYPE_BOTH.equals(typeFromConverter)) {
-          type = HtmlInputTypes.DATETIME_LOCAL;
+          type = DateType.DATETIME_LOCAL;
         } else if (TYPE_TIME.equals(typeFromConverter)) {
-          type = HtmlInputTypes.TIME;
+          type = DateType.TIME;
         } else if (TYPE_LOCAL_DATE.equals(typeFromConverter)) {
-          type = HtmlInputTypes.DATE;
+          type = DateType.DATE;
         } else if (TYPE_LOCAL_DATE_TIME.equals(typeFromConverter)) {
-          type = HtmlInputTypes.DATETIME_LOCAL;
+          type = DateType.DATETIME_LOCAL;
         } else if (TYPE_LOCAL_TIME.equals(typeFromConverter)) {
-          type = HtmlInputTypes.TIME;
+          type = DateType.TIME;
         } else if (TYPE_ZONED_DATE_TIME.equals(typeFromConverter)) {
-          type = HtmlInputTypes.DATETIME_LOCAL;
+          type = DateType.DATETIME_LOCAL;
         } else if (TYPE_OFFSET_DATE_TIME.equals(typeFromConverter)) {
-          type = HtmlInputTypes.DATETIME_LOCAL;
+          type = DateType.DATETIME_LOCAL;
         } else if (TYPE_OFFSET_TIME.equals(typeFromConverter)) {
-          type = HtmlInputTypes.TIME;
+          type = DateType.TIME;
         } else if (TYPE_MONTH.equals(typeFromConverter)) {
-          type = HtmlInputTypes.MONTH;
+          type = DateType.MONTH;
         } else if (TYPE_WEEK.equals(typeFromConverter)) {
-          type = HtmlInputTypes.WEEK;
+          type = DateType.WEEK;
         } else { // unknown type
-          type = HtmlInputTypes.DATE;
+          type = DateType.DATE;
         }
       } else { // no converter
-        type = HtmlInputTypes.DATE;
+        type = DateType.DATE;
       }
     }
 
@@ -357,27 +361,7 @@ public class DateRenderer<T extends AbstractUIDate> extends MessageLayoutRendere
     }
 
     if (pattern == null) {
-      switch (type) {
-        case DATE:
-          pattern = PATTERN_DATE;
-          break;
-        case TIME:
-          pattern = PATTERN_TIME;
-          break;
-        case DATETIME_LOCAL:
-        case DATETIME:
-          pattern = PATTERN_DATETIME;
-          break;
-        case MONTH:
-          pattern = PATTERN_MONTH;
-          break;
-        case WEEK:
-          pattern = PATTERN_WEEK;
-          break;
-        case TEXT:
-        default:
-          pattern = PATTERN_DATETIME;
-      }
+      pattern = type.getPattern();
     }
 
     component.setPattern(pattern);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ConvertDateTimeTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ConvertDateTimeTagDeclaration.java
deleted file mode 100644
index ac3c52f..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ConvertDateTimeTagDeclaration.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.internal.taglib.component;
-
-
-import org.apache.myfaces.tobago.apt.annotation.ConverterTag;
-import org.apache.myfaces.tobago.apt.annotation.Tag;
-import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
-import org.apache.myfaces.tobago.convert.DateTimeConverter;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasFor;
-
-import javax.el.ValueExpression;
-
-/**
- * Register a DateTimeConverter instance on the UIComponent associated with the closest parent UIComponent custom
- * action.
- *
- * @deprecated Since 5.0.0. Should work with &lt;f:convertDateTime%gt; since JSF 2.3.
- */
-@Deprecated
-@Tag(name = "convertDateTime")
-@ConverterTag(
-    converterId = DateTimeConverter.CONVERTER_ID,
-    faceletHandler = "org.apache.myfaces.tobago.facelets.ConvertDateTimeHandler")
-public interface ConvertDateTimeTagDeclaration extends HasFor {
-
-  /**
-   * A ValueExpression that evaluates to an instance of
-   * {@link org.apache.myfaces.tobago.facelets.ConvertDateTimeHandler}.
-   */
-  @TagAttribute(name = "binding", type = "org.apache.myfaces.tobago.convert.DateTimeConverter")
-  void setBinding(ValueExpression binding);
-
-  /**
-   * Locale whose predefined styles for dates and times are used during formatting or parsing. If not specified, the
-   * Locale returned by FacesContext.getViewRoot().getLocale() will be used. Value must be either a VB expression that
-   * evaluates to a java.util.Locale instance, or a String that is valid to pass as the first argument to the
-   * constructor java.util.Locale(String language, String country). The empty string is passed as the second argument.
-   */
-  @TagAttribute(type = "java.lang.Object")
-  void setLocale(ValueExpression locale);
-
-  /**
-   * Custom formatting pattern which determines how the date/time string should be formatted and parsed.
-   * Pattern chars 'G', 'W', 'F', 'K', 'z' and 'X' are not supported.
-   */
-  @TagAttribute()
-  void setPattern(String pattern);
-
-  /**
-   * Time zone in which to interpret any time information in the date String. Value must be either a VB expression that
-   * evaluates to a java.util.TimeZone instance, or a String that is a timezone ID as described in the javadocs for
-   * java.util.TimeZone.getTimeZone().
-   */
-  @TagAttribute(type = "java.lang.Object")
-  void setTimeZone(ValueExpression timeZone);
-
-
-  /**
-   * Specifies what contents the string value will be formatted to include, or parsed expecting. Valid values are
-   * "date", "time", "both", "calendar", "localDate", "localDateTime", "localTime", "offsetTime", "offsetDateTime", and
-   * "zonedDateTime". The values starting with "local", "offset" and "zoned" correspond to Java SE 8 Date Time API
-   * classes in package java.time with the name derived by upper casing the first letter. For example,
-   * java.time.LocalDate for the value "localDate". Default value is "date".
-   */
-  @TagAttribute()
-  void setType(String type);
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/DateTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/DateTagDeclaration.java
index 80e3686..716d96a 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/DateTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/DateTagDeclaration.java
@@ -20,7 +20,6 @@
 package org.apache.myfaces.tobago.internal.taglib.component;
 
 import org.apache.myfaces.tobago.apt.annotation.Behavior;
-import org.apache.myfaces.tobago.apt.annotation.Preliminary;
 import org.apache.myfaces.tobago.apt.annotation.Tag;
 import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
 import org.apache.myfaces.tobago.apt.annotation.UIComponentTag;
@@ -28,6 +27,7 @@ import org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute;
 import org.apache.myfaces.tobago.component.ClientBehaviors;
 import org.apache.myfaces.tobago.component.RendererTypes;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasAccessKey;
+import org.apache.myfaces.tobago.internal.taglib.declaration.HasAutoSpacing;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasConverter;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasConverterMessage;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasHelp;
@@ -42,13 +42,12 @@ import org.apache.myfaces.tobago.internal.taglib.declaration.HasValidator;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasValidatorMessage;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasValue;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasValueChangeListener;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasAutoSpacing;
 import org.apache.myfaces.tobago.internal.taglib.declaration.IsDisabled;
 import org.apache.myfaces.tobago.internal.taglib.declaration.IsFocus;
 import org.apache.myfaces.tobago.internal.taglib.declaration.IsReadonly;
 import org.apache.myfaces.tobago.internal.taglib.declaration.IsRequired;
 import org.apache.myfaces.tobago.internal.taglib.declaration.IsVisual;
-import org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes;
+import org.apache.myfaces.tobago.model.DateType;
 
 import javax.faces.component.UIInput;
 
@@ -99,31 +98,79 @@ public interface DateTagDeclaration
    * Sets the minimum value of the date.
    */
   @TagAttribute
-  @UIComponentTagAttribute(type = {"java.time.LocalDate", "java.util.Date"})
+  @UIComponentTagAttribute(type = {
+      "java.time.LocalDate",
+      "java.time.LocalTime",
+      "java.time.LocalDateTime",
+      "java.time.ZonedDateTime",
+      "java.time.Month",
+      "java.util.Date",
+      "java.util.Calendar",
+      "java.lang.Long",
+      "java.lang.String"
+  })
+  void setValue(String value);
+
+  /**
+   * Sets the minimum value of the date.
+   */
+  @TagAttribute
+  @UIComponentTagAttribute(type = {
+      "java.time.LocalDate",
+      "java.time.LocalTime",
+      "java.time.LocalDateTime",
+      "java.time.ZonedDateTime",
+      "java.time.Month",
+      "java.util.Date",
+      "java.util.Calendar",
+      "java.lang.Long",
+      "java.lang.String"
+  })
   void setMin(String min);
 
   /**
    * Sets the maximum value of the date.
    */
   @TagAttribute
-  @UIComponentTagAttribute(type = {"java.time.LocalDate", "java.util.Date"})
+  @UIComponentTagAttribute(type = {
+      "java.time.LocalDate",
+      "java.time.LocalTime",
+      "java.time.LocalDateTime",
+      "java.time.ZonedDateTime",
+      "java.time.Month",
+      "java.util.Date",
+      "java.util.Calendar",
+      "java.lang.Long",
+      "java.lang.String"
+  })
   void setMax(String max);
 
   /**
-   * XXX Preliminary: check if this is the right way
-   *
+   * Sets the step of a date or time picker. Value is in seconds.
+   * Reasonable values are e.g. 0.001, 1, 5, 10, 60, 300, 3600.
+   * If not set, browsers drop the seconds, so it's the same as the value of 60.
+   * To show seconds use 1.
+   * To show milliseconds use 0.001.
+   * Browser support is in progress.
+   */
+  @TagAttribute
+  @UIComponentTagAttribute(type = {"java.lang.Double"})
+  void setStep(String step);
+
+  /**
    * Type of the date/time input.
+   *
+   * Warning: month and week currently not supported.
    */
-  @Preliminary
   @TagAttribute
   @UIComponentTagAttribute(
-      type = "org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes",
+      type = "org.apache.myfaces.tobago.model.DateType",
       allowedValues = {
-          HtmlInputTypes.STRING_DATE,
-          HtmlInputTypes.STRING_TIME,
-          HtmlInputTypes.STRING_DATETIME_LOCAL,
-          HtmlInputTypes.STRING_MONTH,
-          HtmlInputTypes.STRING_WEEK
+          DateType.STRING_DATE,
+          DateType.STRING_TIME,
+          DateType.STRING_DATETIME_LOCAL,
+          DateType.STRING_MONTH,
+          DateType.STRING_WEEK
       })
   void setType(String type);
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonUtils.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonUtils.java
index 7d1bebb..ea13d87 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonUtils.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonUtils.java
@@ -21,7 +21,6 @@ package org.apache.myfaces.tobago.internal.util;
 
 import org.apache.myfaces.tobago.component.ClientBehaviors;
 import org.apache.myfaces.tobago.context.Markup;
-import org.apache.myfaces.tobago.internal.context.DateTimeI18n;
 import org.apache.myfaces.tobago.internal.renderkit.Collapse;
 import org.apache.myfaces.tobago.internal.renderkit.Command;
 import org.apache.myfaces.tobago.internal.renderkit.CommandMap;
@@ -240,31 +239,6 @@ public class JsonUtils {
     builder.append("},");
   }
 
-  public static String encode(final DateTimeI18n dateTimeI18n) {
-    final StringBuilder builder = new StringBuilder();
-    builder.append("{");
-    final int initialLength = builder.length();
-
-    encode(builder, "months", dateTimeI18n.getMonths());
-    encode(builder, "monthsShort", dateTimeI18n.getMonthsShort());
-    encode(builder, "days", dateTimeI18n.getDays());
-    encode(builder, "daysShort", dateTimeI18n.getDaysShort());
-    encode(builder, "daysMin", dateTimeI18n.getDaysMin());
-    encode(builder, "firstDay", dateTimeI18n.getWeekStart());
-    encode(builder, "minDays", dateTimeI18n.getMinDays());
-    encode(builder, "today", dateTimeI18n.getToday());
-    encode(builder, "cancel", dateTimeI18n.getCancel());
-    encode(builder, "clear", dateTimeI18n.getClear());
-    encode(builder, "week", dateTimeI18n.getWeek());
-
-    if (builder.length() - initialLength > 0) {
-      assert builder.charAt(builder.length() - 1) == ',';
-      builder.deleteCharAt(builder.length() - 1);
-    }
-    builder.append("}");
-    return builder.toString();
-  }
-
   public static String encode(final String[] strings) {
     if (strings == null) {
       return null;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateModel.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateModel.java
deleted file mode 100644
index 77b3912..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateModel.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.model;
-
-import java.util.Calendar;
-import java.util.Locale;
-
-public class DateModel {
-
-  private int year;
-  private int month;
-  private int day;
-
-  public DateModel(final int year, final int month, final int day) {
-    this.year = year;
-    this.month = month;
-    this.day = day;
-  }
-
-  public DateModel(final Calendar calendar) {
-    this.year = calendar.get(Calendar.YEAR);
-    this.month = calendar.get(Calendar.MONTH) + 1;
-    this.day = calendar.get(Calendar.DAY_OF_MONTH);
-  }
-
-  public int getYear() {
-    return year;
-  }
-
-  public void setYear(final int year) {
-    this.year = year;
-  }
-
-  public int getMonth() {
-    return month;
-  }
-
-  public void setMonth(final int month) {
-    this.month = month;
-  }
-
-  public int getDay() {
-    return day;
-  }
-
-  public void setDay(final int day) {
-    this.day = day;
-  }
-
-  public Calendar getCalendar() {
-    return getCalendar(null);
-  }
-
-  public Calendar getCalendar(final Locale locale) {
-    final Calendar calendar = locale != null
-        ? Calendar.getInstance(locale) : Calendar.getInstance();
-    calendar.set(year, month - 1, day);
-    return calendar;
-  }
-
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateType.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateType.java
new file mode 100644
index 0000000..854f950
--- /dev/null
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateType.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.model;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
+
+/**
+ * Types of date/time-based input fields.
+ *
+ * @since 5.0.0
+ */
+public final class DateType implements Serializable {
+
+  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  public static final String STRING_DATE = "date";
+  public static final String STRING_DATETIME_LOCAL = "datetime-local";
+  public static final String STRING_MONTH = "month";
+  public static final String STRING_TIME = "time";
+  public static final String STRING_WEEK = "week";
+
+  public static final String PATTERN_DATE = "yyyy-MM-dd";
+  public static final String PATTERN_DATETIME_LOCAL_MILLIS = "yyyy-MM-dd'T'HH:mm:ss.SSS";
+  public static final String PATTERN_DATETIME_LOCAL_SECONDS = "yyyy-MM-dd'T'HH:mm:ss";
+  public static final String PATTERN_DATETIME_LOCAL = "yyyy-MM-dd'T'HH:mm";
+  public static final String PATTERN_TIME_MILLIS = "HH:mm:ss.SSS";
+  public static final String PATTERN_TIME_SECONDS = "HH:mm:ss";
+  public static final String PATTERN_TIME = "HH:mm";
+  public static final String PATTERN_MONTH = "yyyy-MM";
+  public static final String PATTERN_WEEK = "yyyy-'W'ww";
+
+  public static final DateType DATE = new DateType(STRING_DATE, PATTERN_DATE);
+  public static final DateType DATETIME_LOCAL = new DateType(STRING_DATETIME_LOCAL, PATTERN_DATETIME_LOCAL);
+  public static final DateType MONTH = new DateType(STRING_MONTH, PATTERN_MONTH);
+  public static final DateType TIME = new DateType(STRING_TIME, PATTERN_TIME);
+  public static final DateType WEEK = new DateType(STRING_WEEK, PATTERN_WEEK);
+
+  private String name;
+  private String pattern;
+
+  public DateType(final String name, final String pattern) {
+    this.name = name;
+    this.pattern = pattern;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getPattern() {
+    return pattern;
+  }
+
+  public void setPattern(String pattern) {
+    this.pattern = pattern;
+  }
+
+  public static DateType valueOf(String text) {
+    switch (text) {
+      case "date":
+        return DATE;
+      case "datetime-local":
+        return DATETIME_LOCAL;
+      case "month":
+        return MONTH;
+      case "time":
+        return TIME;
+      case "week":
+        return WEEK;
+      default:
+        LOG.error("Unknown date type '{}'", text);
+        return null;
+    }
+  }
+}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlInputTypesEditor.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateTypeEditor.java
similarity index 72%
rename from tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlInputTypesEditor.java
rename to tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateTypeEditor.java
index 63fdcdc..824bafe 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlInputTypesEditor.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/model/DateTypeEditor.java
@@ -17,25 +17,24 @@
  * under the License.
  */
 
-package org.apache.myfaces.tobago.renderkit.html;
-
-import org.apache.myfaces.tobago.apt.annotation.Preliminary;
+package org.apache.myfaces.tobago.model;
 
 import java.beans.PropertyEditorSupport;
 
 /**
- * XXX Preliminary: check if this is the right way
- *
- * Converter for {@link org.apache.myfaces.tobago.renderkit.html.HtmlInputTypes}
+ * Converter for {@link DateType}
  *
  * @since 5.0.0
  */
-@Preliminary
-public class HtmlInputTypesEditor extends PropertyEditorSupport {
+public final class DateTypeEditor extends PropertyEditorSupport {
 
   @Override
   public void setAsText(final String text) throws IllegalArgumentException {
-    setValue(HtmlInputTypes.valueOf(text));
+    setValue(DateType.valueOf(text));
   }
 
+  @Override
+  public String getAsText() {
+    return ((DateType) getValue()).getName();
+  }
 }
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRendererUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRendererUnitTest.java
index c54a7a4..f4c3ca6 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRendererUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/renderer/DateRendererUnitTest.java
@@ -121,6 +121,25 @@ public class DateRendererUnitTest extends RendererTestBase {
   }
 
   @Test
+  public void dateTimeStep() throws IOException {
+
+    final UIDate d = (UIDate) ComponentUtils.createComponent(
+        facesContext, Tags.date.componentType(), RendererTypes.Date, "id");
+    d.setValue(SPUTNIK_DATE);
+    d.setStep(.001);
+
+    DateTimeConverter c = new DateTimeConverter();
+    c.setType("time");
+    c.setPattern("HH:mm:ss.SSS");
+    d.setConverter(c);
+
+    log(d);
+    d.encodeAll(facesContext);
+
+    Assertions.assertEquals(loadHtml("renderer/date/dateTimeStep.html"), formattedResult());
+  }
+
+  @Test
   public void testLabel() throws IOException, ParseException {
 
     final UIDate d = (UIDate) ComponentUtils.createComponent(
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java
index abf3e0e..ea8f5ed 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java
@@ -26,7 +26,6 @@ import org.apache.myfaces.tobago.component.Tags;
 import org.apache.myfaces.tobago.context.Markup;
 import org.apache.myfaces.tobago.internal.component.AbstractUICommand;
 import org.apache.myfaces.tobago.internal.config.AbstractTobagoTestBase;
-import org.apache.myfaces.tobago.internal.context.DateTimeI18n;
 import org.apache.myfaces.tobago.internal.renderkit.Collapse;
 import org.apache.myfaces.tobago.internal.renderkit.Command;
 import org.apache.myfaces.tobago.internal.renderkit.CommandMap;
@@ -40,7 +39,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Locale;
 
 // using ' instead of " to make it better readable.
 
@@ -123,27 +121,6 @@ public class JsonUtilsUnitTest extends AbstractTobagoTestBase {
   }
 
   @Test
-  public void months() {
-    final DateTimeI18n dateTimeI18n = DateTimeI18n.valueOf(Locale.GERMANY);
-    final String marchShort = dateTimeI18n.getMonthsShort()[2]; // different with JDK 1.8.0_51 and 1.8.0_60
-    final String[] daysShort = dateTimeI18n.getDaysShort(); // different with JDK 1.8.0    and 1.9.0
-    final String[] daysMin = dateTimeI18n.getDaysMin(); // different with JDK 1.8.0 and 1.9.0
-    final String expected
-        = ("{'months':['Januar','Februar','März','April','Mai','Juni',"
-        + "'Juli','August','September','Oktober','November','Dezember'],"
-        + "'monthsShort':['Jan','Feb','" + marchShort + "','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],"
-        + "'days':['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],"
-        + "'daysShort':['" + daysShort[0] + "','" + daysShort[1] + "','" + daysShort[2] + "','"
-        + daysShort[3] + "','" + daysShort[4] + "','" + daysShort[5] + "','" + daysShort[6] + "'],"
-        + "'daysMin':['" + daysMin[0] + "','" + daysMin[1] + "','" + daysMin[2] + "','"
-        + daysMin[3] + "','" + daysMin[4] + "','" + daysMin[5] + "','" + daysMin[6] + "'],"
-        + "'firstDay':1,'minDays':4,'today':'Today','cancel':'Cancel','clear':'Clear','week':'Week'}")
-        .replaceAll("'", "\"");
-
-    Assertions.assertEquals(expected, JsonUtils.encode(dateTimeI18n));
-  }
-
-  @Test
   public void decodeIntegerArray() {
 
     Assertions.assertEquals(Arrays.asList(1, 2, 3, 4), JsonUtils.decodeIntegerArray("[1,2,3,4]"));
diff --git a/tobago-core/src/test/resources/renderer/date/dateAuto.html b/tobago-core/src/test/resources/renderer/date/dateAuto.html
index 5eef08f..93f21ee 100644
--- a/tobago-core/src/test/resources/renderer/date/dateAuto.html
+++ b/tobago-core/src/test/resources/renderer/date/dateAuto.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='date' name='id' id='id::field' value='1957-10-04' class='form-control'>
diff --git a/tobago-core/src/test/resources/renderer/date/dateBoth.html b/tobago-core/src/test/resources/renderer/date/dateBoth.html
index b588f1f..66b92cd 100644
--- a/tobago-core/src/test/resources/renderer/date/dateBoth.html
+++ b/tobago-core/src/test/resources/renderer/date/dateBoth.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='datetime-local' name='id' id='id::field' value='1957-10-04T19:28:34' class='form-control'>
diff --git a/tobago-core/src/test/resources/renderer/date/dateDate.html b/tobago-core/src/test/resources/renderer/date/dateDate.html
index 5eef08f..93f21ee 100644
--- a/tobago-core/src/test/resources/renderer/date/dateDate.html
+++ b/tobago-core/src/test/resources/renderer/date/dateDate.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='date' name='id' id='id::field' value='1957-10-04' class='form-control'>
diff --git a/tobago-core/src/test/resources/renderer/date/dateTime.html b/tobago-core/src/test/resources/renderer/date/dateTime.html
index 9b0cc0a..f511e14 100644
--- a/tobago-core/src/test/resources/renderer/date/dateTime.html
+++ b/tobago-core/src/test/resources/renderer/date/dateTime.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='time' name='id' id='id::field' value='19:28:34' class='form-control'>
diff --git a/tobago-theme/tobago-theme-standard/src/main/scss/tobago-theme.scss b/tobago-core/src/test/resources/renderer/date/dateTimeStep.html
similarity index 72%
copy from tobago-theme/tobago-theme-standard/src/main/scss/tobago-theme.scss
copy to tobago-core/src/test/resources/renderer/date/dateTimeStep.html
index 72ffaeb..c9eb855 100644
--- a/tobago-theme/tobago-theme-standard/src/main/scss/tobago-theme.scss
+++ b/tobago-core/src/test/resources/renderer/date/dateTimeStep.html
@@ -1,4 +1,4 @@
-/*
+<!--
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -13,13 +13,12 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */
+-->
 
-@import "node_modules/bootstrap/scss/bootstrap";
-
-// XXX patched because of bs5 (begin)
-//@import "node_modules/vanillajs-datepicker/sass/datepicker-bs4";
-@import "../../../../src/main/scss/datepicker-bs5";
-// XXX patched because of bs5 (end)
-
-@import "../../../../src/main/scss/_tobago";
+<tobago-date id='id' class='tobago-auto-spacing'>
+  <div class='tobago-input-group-outer'>
+    <div class='input-group'>
+      <input type='time' step='0.001' name='id' id='id::field' value='19:28:34.123' class='form-control'>
+    </div>
+  </div>
+</tobago-date>
\ No newline at end of file
diff --git a/tobago-core/src/test/resources/renderer/date/localDateAuto.html b/tobago-core/src/test/resources/renderer/date/localDateAuto.html
index 118a46f..53e7f1e 100644
--- a/tobago-core/src/test/resources/renderer/date/localDateAuto.html
+++ b/tobago-core/src/test/resources/renderer/date/localDateAuto.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='date' name='id' id='id::field' value='1957-10-05' class='form-control'>
diff --git a/tobago-core/src/test/resources/renderer/date/localDateTimeAuto.html b/tobago-core/src/test/resources/renderer/date/localDateTimeAuto.html
index 6e0f137..5a2eed0 100644
--- a/tobago-core/src/test/resources/renderer/date/localDateTimeAuto.html
+++ b/tobago-core/src/test/resources/renderer/date/localDateTimeAuto.html
@@ -15,10 +15,10 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
-      <input type='datetime-local' name='id' id='id::field' value='1957-10-05T00:28:34.123' class='form-control'>
+      <input type='datetime-local' name='id' id='id::field' value='1957-10-05T00:28' class='form-control'>
     </div>
   </div>
 </tobago-date>
\ No newline at end of file
diff --git a/tobago-core/src/test/resources/renderer/date/localTimeAuto.html b/tobago-core/src/test/resources/renderer/date/localTimeAuto.html
index cbc64cb..0407684 100644
--- a/tobago-core/src/test/resources/renderer/date/localTimeAuto.html
+++ b/tobago-core/src/test/resources/renderer/date/localTimeAuto.html
@@ -15,10 +15,10 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
-      <input type='time' name='id' id='id::field' value='00:28:34.123' class='form-control'>
+      <input type='time' name='id' id='id::field' value='00:28' class='form-control'>
     </div>
   </div>
 </tobago-date>
\ No newline at end of file
diff --git a/tobago-core/src/test/resources/renderer/date/minMax.html b/tobago-core/src/test/resources/renderer/date/minMax.html
index a69abbc..fd7c193 100644
--- a/tobago-core/src/test/resources/renderer/date/minMax.html
+++ b/tobago-core/src/test/resources/renderer/date/minMax.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='date' name='id' id='id::field' value='1957-10-05' min='1957-09-05' max='1957-11-04' class='form-control'>
diff --git a/tobago-core/src/test/resources/renderer/date/testLabel.html b/tobago-core/src/test/resources/renderer/date/testLabel.html
index 6770b4d..59e274b 100644
--- a/tobago-core/src/test/resources/renderer/date/testLabel.html
+++ b/tobago-core/src/test/resources/renderer/date/testLabel.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-label-container tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0," [...]
+<tobago-date id='id' class='tobago-label-container tobago-auto-spacing'>
   <label for='id::field' class='col-form-label'>Label</label>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
diff --git a/tobago-core/src/test/resources/renderer/date/testTodayButton.html b/tobago-core/src/test/resources/renderer/date/testTodayButton.html
index 278cbb6..13e79ee 100644
--- a/tobago-core/src/test/resources/renderer/date/testTodayButton.html
+++ b/tobago-core/src/test/resources/renderer/date/testTodayButton.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-label-container tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0," [...]
+<tobago-date id='id' class='tobago-label-container tobago-auto-spacing' today-button='today-button'>
   <label for='id::field' class='col-form-label'>Label</label>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
diff --git a/tobago-core/src/test/resources/renderer/date/text.html b/tobago-core/src/test/resources/renderer/date/text.html
index 4895e54..a02a3ee 100644
--- a/tobago-core/src/test/resources/renderer/date/text.html
+++ b/tobago-core/src/test/resources/renderer/date/text.html
@@ -15,7 +15,7 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' date-pattern='dd.mm.yyyy' time-pattern='HH:mm' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fr [...]
+<tobago-date id='id' class='tobago-auto-spacing' date-pattern='dd.mm.yyyy' time-pattern='HH:mm'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <input type='text' name='id' id='id::field' class='form-control'>
diff --git a/tobago-core/src/test/resources/renderer/date/zonedDateTimeAuto.html b/tobago-core/src/test/resources/renderer/date/zonedDateTimeAuto.html
index 6e0f137..5a2eed0 100644
--- a/tobago-core/src/test/resources/renderer/date/zonedDateTimeAuto.html
+++ b/tobago-core/src/test/resources/renderer/date/zonedDateTimeAuto.html
@@ -15,10 +15,10 @@
  * limitations under the License.
 -->
 
-<tobago-date id='id' class='tobago-auto-spacing' i18n='{"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"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"daysShort":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"daysMin":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"firstDay":0,"minDays":1,"today":"Tod [...]
+<tobago-date id='id' class='tobago-auto-spacing'>
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
-      <input type='datetime-local' name='id' id='id::field' value='1957-10-05T00:28:34.123' class='form-control'>
+      <input type='datetime-local' name='id' id='id::field' value='1957-10-05T00:28' class='form-control'>
     </div>
   </div>
 </tobago-date>
\ No newline at end of file
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/ConvertDateTimeController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/ConvertDateTimeController.java
deleted file mode 100644
index 398db76..0000000
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/ConvertDateTimeController.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.myfaces.tobago.example.demo;
-
-import javax.enterprise.context.RequestScoped;
-import javax.inject.Named;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
-import java.time.ZonedDateTime;
-import java.util.Calendar;
-import java.util.Date;
-
-@RequestScoped
-@Named
-public class ConvertDateTimeController {
-
-  private Date myFacesDate;
-  private Date tobagoDate;
-  private Calendar calendar;
-  private LocalDate myFacesLocalDate;
-  private LocalDate tobagoLocalDate;
-  private LocalTime myFacesLocalTime;
-  private LocalTime tobagoLocalTime;
-  private LocalDateTime myFacesLocalDateTime;
-  private LocalDateTime tobagoLocalDateTime;
-  private OffsetTime myFacesOffsetTime;
-  private OffsetTime tobagoOffsetTime;
-  private OffsetDateTime myFacesOffsetDateTime;
-  private OffsetDateTime tobagoOffsetDateTime;
-  private ZonedDateTime myFacesZonedDateTime;
-  private ZonedDateTime tobagoZonedDateTime;
-
-  public Date getMyFacesDate() {
-    return myFacesDate;
-  }
-
-  public void setMyFacesDate(Date myFacesDate) {
-    this.myFacesDate = myFacesDate;
-  }
-
-  public Date getTobagoDate() {
-    return tobagoDate;
-  }
-
-  public void setTobagoDate(Date tobagoDate) {
-    this.tobagoDate = tobagoDate;
-  }
-
-  public Calendar getCalendar() {
-    return calendar;
-  }
-
-  public void setCalendar(Calendar calendar) {
-    this.calendar = calendar;
-  }
-
-  public LocalDate getMyFacesLocalDate() {
-    return myFacesLocalDate;
-  }
-
-  public void setMyFacesLocalDate(LocalDate myFacesLocalDate) {
-    this.myFacesLocalDate = myFacesLocalDate;
-  }
-
-  public LocalDate getTobagoLocalDate() {
-    return tobagoLocalDate;
-  }
-
-  public void setTobagoLocalDate(LocalDate tobagoLocalDate) {
-    this.tobagoLocalDate = tobagoLocalDate;
-  }
-
-  public LocalTime getMyFacesLocalTime() {
-    return myFacesLocalTime;
-  }
-
-  public void setMyFacesLocalTime(LocalTime myFacesLocalTime) {
-    this.myFacesLocalTime = myFacesLocalTime;
-  }
-
-  public LocalTime getTobagoLocalTime() {
-    return tobagoLocalTime;
-  }
-
-  public void setTobagoLocalTime(LocalTime tobagoLocalTime) {
-    this.tobagoLocalTime = tobagoLocalTime;
-  }
-
-  public LocalDateTime getMyFacesLocalDateTime() {
-    return myFacesLocalDateTime;
-  }
-
-  public void setMyFacesLocalDateTime(LocalDateTime myFacesLocalDateTime) {
-    this.myFacesLocalDateTime = myFacesLocalDateTime;
-  }
-
-  public LocalDateTime getTobagoLocalDateTime() {
-    return tobagoLocalDateTime;
-  }
-
-  public void setTobagoLocalDateTime(LocalDateTime tobagoLocalDateTime) {
-    this.tobagoLocalDateTime = tobagoLocalDateTime;
-  }
-
-  public OffsetTime getMyFacesOffsetTime() {
-    return myFacesOffsetTime;
-  }
-
-  public void setMyFacesOffsetTime(OffsetTime myFacesOffsetTime) {
-    this.myFacesOffsetTime = myFacesOffsetTime;
-  }
-
-  public OffsetTime getTobagoOffsetTime() {
-    return tobagoOffsetTime;
-  }
-
-  public void setTobagoOffsetTime(OffsetTime tobagoOffsetTime) {
-    this.tobagoOffsetTime = tobagoOffsetTime;
-  }
-
-  public OffsetDateTime getMyFacesOffsetDateTime() {
-    return myFacesOffsetDateTime;
-  }
-
-  public void setMyFacesOffsetDateTime(OffsetDateTime myFacesOffsetDateTime) {
-    this.myFacesOffsetDateTime = myFacesOffsetDateTime;
-  }
-
-  public OffsetDateTime getTobagoOffsetDateTime() {
-    return tobagoOffsetDateTime;
-  }
-
-  public void setTobagoOffsetDateTime(OffsetDateTime tobagoOffsetDateTime) {
-    this.tobagoOffsetDateTime = tobagoOffsetDateTime;
-  }
-
-  public ZonedDateTime getMyFacesZonedDateTime() {
-    return myFacesZonedDateTime;
-  }
-
-  public void setMyFacesZonedDateTime(ZonedDateTime myFacesZonedDateTime) {
-    this.myFacesZonedDateTime = myFacesZonedDateTime;
-  }
-
-  public ZonedDateTime getTobagoZonedDateTime() {
-    return tobagoZonedDateTime;
-  }
-
-  public void setTobagoZonedDateTime(ZonedDateTime tobagoZonedDateTime) {
-    this.tobagoZonedDateTime = tobagoZonedDateTime;
-  }
-}
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/CurrentValueController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/CurrentValueController.java
index b776254..bb7c818 100644
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/CurrentValueController.java
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/CurrentValueController.java
@@ -19,39 +19,23 @@
 
 package org.apache.myfaces.tobago.example.demo;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import javax.enterprise.context.RequestScoped;
 import javax.inject.Named;
-import java.lang.invoke.MethodHandles;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
+import java.time.LocalDate;
 import java.util.Currency;
-import java.util.Date;
-import java.util.GregorianCalendar;
 
 @Named
 @RequestScoped
 public class CurrentValueController {
 
-  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
   private String string;
-  private Date date;
+  private LocalDate date;
   private Currency currency;
 
   public CurrentValueController() {
 
     string = "simple string";
-
-    try {
-      this.date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("1969-07-24 16:50:35");
-    } catch (final ParseException e) {
-      LOG.error("", e);
-    }
-
+    date = LocalDate.of(1969, 7, 24);
     currency = Currency.getInstance("TTD");
   }
 
@@ -59,14 +43,12 @@ public class CurrentValueController {
     return text != null ? text.toUpperCase() : null;
   }
 
-  public Date plus50(final Date base) {
+  public LocalDate plus50(final LocalDate base) {
     if (date == null) {
       return null;
+    } else {
+      return date.plusYears(50);
     }
-    final GregorianCalendar calendar = new GregorianCalendar();
-    calendar.setTime(date);
-    calendar.add(Calendar.YEAR, 50);
-    return calendar.getTime();
   }
 
   public Currency toCurrency(final String currencyString) {
@@ -77,7 +59,7 @@ public class CurrentValueController {
     return string;
   }
 
-  public Date getDate() {
+  public LocalDate getDate() {
     return date;
   }
 
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/DateTestController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/DateTestController.java
new file mode 100644
index 0000000..fa4a64e
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/DateTestController.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.tobago.example.demo;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Named;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+@RequestScoped
+@Named
+public class DateTestController {
+
+  private LocalDate localDate;
+  private LocalTime localTime;
+  private LocalTime localTimeStepA;
+  private LocalTime localTimeStepB;
+  private LocalDateTime localDateTime;
+  private LocalDateTime localDateTimeStepA;
+  private LocalDateTime localDateTimeStepB;
+  private LocalDate month;
+  private LocalDate week;
+  private Long longValue;
+
+  public LocalDate getLocalDate() {
+    return localDate;
+  }
+
+  public void setLocalDate(LocalDate localDate) {
+    this.localDate = localDate;
+  }
+
+  public LocalTime getLocalTime() {
+    return localTime;
+  }
+
+  public void setLocalTime(LocalTime localTime) {
+    this.localTime = localTime;
+  }
+
+  public LocalTime getLocalTimeStepA() {
+    return localTimeStepA;
+  }
+
+  public void setLocalTimeStepA(LocalTime localTimeStepA) {
+    this.localTimeStepA = localTimeStepA;
+  }
+
+  public LocalTime getLocalTimeStepB() {
+    return localTimeStepB;
+  }
+
+  public void setLocalTimeStepB(LocalTime localTimeStepB) {
+    this.localTimeStepB = localTimeStepB;
+  }
+
+  public LocalDateTime getLocalDateTime() {
+    return localDateTime;
+  }
+
+  public void setLocalDateTime(LocalDateTime localDateTime) {
+    this.localDateTime = localDateTime;
+  }
+
+  public LocalDateTime getLocalDateTimeStepA() {
+    return localDateTimeStepA;
+  }
+
+  public void setLocalDateTimeStepA(LocalDateTime localDateTimeStepA) {
+    this.localDateTimeStepA = localDateTimeStepA;
+  }
+
+  public LocalDateTime getLocalDateTimeStepB() {
+    return localDateTimeStepB;
+  }
+
+  public void setLocalDateTimeStepB(LocalDateTime localDateTimeStepB) {
+    this.localDateTimeStepB = localDateTimeStepB;
+  }
+
+  public LocalDate getMonth() {
+    return month;
+  }
+
+  public void setMonth(LocalDate month) {
+    this.month = month;
+  }
+
+  public LocalDate getWeek() {
+    return week;
+  }
+
+  public void setWeek(LocalDate week) {
+    this.week = week;
+  }
+
+  public Long getLongValue() {
+    return longValue;
+  }
+
+  public void setLongValue(Long longValue) {
+    this.longValue = longValue;
+  }
+}
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
index 4610b1c..26e7957 100644
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
@@ -29,19 +29,13 @@ import org.slf4j.LoggerFactory;
 
 import javax.annotation.PostConstruct;
 import javax.enterprise.context.SessionScoped;
-import javax.faces.component.UIComponent;
 import javax.faces.component.UIData;
-import javax.faces.context.FacesContext;
-import javax.faces.convert.DateTimeConverter;
 import javax.faces.event.FacesEvent;
 import javax.inject.Inject;
 import javax.inject.Named;
 import java.io.Serializable;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -155,31 +149,6 @@ public class SheetController implements Serializable {
     return columnEventSample;
   }
 
-  public javax.faces.convert.Converter getYearConverter() {
-
-    final DateTimeConverter dateTimeConverter = new DateTimeConverter() {
-
-      @Override
-      public Object getAsObject(final FacesContext facesContext, final UIComponent uiComponent, final String value) {
-        final Date date = (Date) super.getAsObject(facesContext, uiComponent, value);
-        final Calendar calendar = GregorianCalendar.getInstance(facesContext.getViewRoot().getLocale());
-        calendar.setTime(date);
-        return calendar.get(Calendar.YEAR);
-      }
-
-      @Override
-      public String getAsString(final FacesContext facesContext, final UIComponent uiComponent, final Object value) {
-        final Calendar calendar = GregorianCalendar.getInstance(facesContext.getViewRoot().getLocale());
-        calendar.set(Calendar.YEAR, (Integer) value);
-        final Date date = calendar.getTime();
-        return super.getAsString(facesContext, uiComponent, date);
-      }
-    };
-
-    dateTimeConverter.setPattern("yyyy");
-    return dateTimeConverter;
-  }
-
   public Selectable getSelectable() {
     return selectable;
   }
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/000-intro/50-migration/95-migration/4.0_to_5.0.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/000-intro/50-migration/95-migration/4.0_to_5.0.xhtml
index be9247d..575a7fb 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/000-intro/50-migration/95-migration/4.0_to_5.0.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/000-intro/50-migration/95-migration/4.0_to_5.0.xhtml
@@ -69,6 +69,15 @@
         has been removed. Please use the <code class="language-markup">&lt;tc:metaLink></code> tag instead.
       </tc:section>
 
+      <tc:section label="Date Input">
+        <ul>
+          <li>Completely refactored</li>
+          <li>Support for HTML input types: date, time, datetime-local</li>
+          <li>Droped support for java.util.Calendar</li>
+          <li>Replace &lt;tc:convertDateTime> with &lt;f:convertDateTime></li>
+        </ul>
+      </tc:section>
+
     </tc:section>
 
     <tc:section id="java" label="Java API">
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/010-input/40-date/Date.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/010-input/40-date/Date.xhtml
index 475b0bb..d6260d3 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/010-input/40-date/Date.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/010-input/40-date/Date.xhtml
@@ -24,7 +24,7 @@
                 xmlns:f="http://xmlns.jcp.org/jsf/core">
 
   <p>The <code class="language-markup">&lt;tc:date/&gt;</code>
-    tag create an input field with a button to open a calendar to edit the date.
+    tag create an input field for a date or time.
     The date can also be edited in the textfield.</p>
   <p>Tag Library Documentation:
     <tc:link label="&lt;tc:date/>" image="#{request.contextPath}/image/feather-leaf.png" link="#{apiController.tldBase}/#{apiController.currentRelease}/tld/tc/date.html"/>
@@ -34,7 +34,7 @@
   </p>
 
   <tc:section label="Basics">
-    <p>In general, a date had a label. To get a label use the <code>label</code> attribute, <code>&lt;tc:in&gt;</code>.</p>
+    <p>In general, a date has a label. To get a label use the <code>label</code> attribute.</p>
         <demo-highlight language="markup">&lt;tc:date label="Date" value="\#{dateController.sputnikLd}"/&gt;</demo-highlight>
     <tc:date id="dNormal" label="Date" value="#{dateController.sputnikLd}"/>
     <tc:date id="dReadonly" label="Read Only" readonly="true" value="#{dateController.now}"/>
@@ -64,7 +64,6 @@
       <li><tc:link label="java.time.LocalDateTime" link="https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html"/></li>
       <li><tc:link label="java.time.LocalTime" link="https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html"/></li>
       <li><tc:link label="java.util.Date" link="https://docs.oracle.com/javase/8/docs/api/java/util/Date.html"/> (not recommended)</li>
-      <li><tc:link label="java.lang.Long" link="https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html"/> (not recommended)</li>
       <li><tc:link label="java.lang.String" link="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html"/> for plain text (TBD)</li>
     </ul>
     <p>
@@ -91,7 +90,6 @@
       <f:convertDateTime type="time"/>
     </tc:date>
     <tc:date id="typeLong" label="Long" value="#{dateController.typeLong}"/>
-<!--    <tc:date id="typeCalendar" label="Calendar" value="#{dateController.typeCalendar}"/>-->
     <tc:date id="typeString" label="String" value="#{dateController.typeString}"/>
   </tc:section>
 
@@ -183,6 +181,7 @@
       <tc:date id="dateTodayButton" label="Today Button" value="#{dateController.now}" todayButton="true">
         <f:convertDateTime pattern="dd.MM.yyyy"/>
       </tc:date>
+      <tc:badge markup="warning" value="Attention:"/> Currently not supported!
     </tc:section>
   </tc:section>
   <tc:section label="Styles">
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/080-sheet/80-editable/Sheet_Editable.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/080-sheet/80-editable/Sheet_Editable.xhtml
index 90c9137..1bda91c 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/080-sheet/80-editable/Sheet_Editable.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/080-sheet/80-editable/Sheet_Editable.xhtml
@@ -50,7 +50,7 @@
         <tc:in value="#{object.discoverer}" labelLayout="skip"/>
       </tc:column>
       <tc:column label="Year">
-        <tc:date value="#{object.discoverYear}" converter="#{sheetController.yearConverter}" labelLayout="skip"/>
+        <tc:in value="#{object.discoverYear}" labelLayout="skip"/>
       </tc:column>
     </tc:sheet>
     <tc:button label="Submit">
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1041-date-tobagoConverter/Date_TobagoConverter.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1041-date-tobagoConverter/Date_TobagoConverter.test.js
deleted file mode 100644
index a0eeda9..0000000
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1041-date-tobagoConverter/Date_TobagoConverter.test.js
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
-
-it("not implemented yet", function (done) {
-  let test = new JasmineTestTool(done);
-  test.do(() => fail("not implemented yet"));
-  test.start();
-});
-
-/*
-import {querySelectorFn} from "/script/tobago-test.js";
-import {TobagoTestTool} from "/tobago/test/tobago-test-tool.js";
-
-QUnit.test("Date - f:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:myfacesDateInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:myfacesDateInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:myfacesDateOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "dd.MM.yyyy HH:mm:ss", true, true,
-      "14.12.2018 12:34:56", "14.12.2018 12:34:56");
-});
-
-QUnit.test("Date - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoDateInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoDateInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoDateOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "dd.MM.yyyy HH:mm:ss", true, true,
-      "14.12.2018 12:34:56", "14.12.2018 12:34:56");
-});
-
-QUnit.test("Calendar - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoDateInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoDateInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoDateOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "dd.MM.yyyy HH:mm:ss", true, true,
-      "14.12.2018 12:34:56", "14.12.2018 12:34:56");
-});
-
-QUnit.test("LocalDate - f:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalDateInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalDateInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalDateOutput .tobago-out");
-
-  if (inputFn() !== null) {
-    testConvertDateTime(assert,
-        inputFn, datepickerButtonFn, outputFn,
-        "dd.MM.yyyy", true, false,
-        "14.12.2018", "14.12.2018");
-  } else {
-    assert.ok(true, "MyFaces 2.3 not activated");
-  }
-});
-
-QUnit.test("LocalDate - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalDateInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalDateInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalDateOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "dd.MM.yyyy", true, false,
-      "14.12.2018", "14.12.2018");
-});
-
-QUnit.test("LocalTime - f:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalTimeOutput .tobago-out");
-
-  if (inputFn() !== null) {
-    testConvertDateTime(assert,
-        inputFn, datepickerButtonFn, outputFn,
-        "HH:mm:ss", false, true,
-        "12:34:56", "12:34:56");
-  } else {
-    assert.ok(true, "MyFaces 2.3 not activated");
-  }
-});
-
-QUnit.test("LocalTime - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalTimeOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "HH:mm:ss", false, true,
-      "12:34:56", "12:34:56");
-});
-
-QUnit.test("LocalDateTime - f:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalDateTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalDateTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:myfacesLocalDateTimeOutput .tobago-out");
-
-  if (inputFn() !== null) {
-    testConvertDateTime(assert,
-        inputFn, datepickerButtonFn, outputFn,
-        "dd.MM.yyyy HH:mm:ss", true, true,
-        "14.12.2018 12:34:56", "14.12.2018 12:34:56");
-  } else {
-    assert.ok(true, "MyFaces 2.3 not activated");
-  }
-});
-
-QUnit.test("LocalDateTime - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalDateTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalDateTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoLocalDateTimeOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "dd.MM.yyyy HH:mm:ss", true, true,
-      "14.12.2018 12:34:56", "14.12.2018 12:34:56");
-});
-
-QUnit.test("OffsetTime - f:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:myfacesOffsetTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:myfacesOffsetTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:myfacesOffsetTimeOutput .tobago-out");
-
-  if (inputFn() !== null) {
-    testConvertDateTime(assert,
-        inputFn, datepickerButtonFn, outputFn,
-        "HH:mm:ss Z", false, true,
-        "12:34:56 +0200", "12:34:56");
-  } else {
-    assert.ok(true, "MyFaces 2.3 not activated");
-  }
-});
-
-QUnit.test("OffsetTime - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoOffsetTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoOffsetTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoOffsetTimeOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "HH:mm:ss Z", false, true,
-      "12:34:56 +0200", "12:34:56");
-});
-
-QUnit.test("OffsetDateTime - f:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:myfacesOffsetDateTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:myfacesOffsetDateTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:myfacesOffsetDateTimeOutput .tobago-out");
-
-  if (inputFn() !== null) {
-    testConvertDateTime(assert,
-        inputFn, datepickerButtonFn, outputFn,
-        "dd.MM.yyyy HH:mm:ss Z", true, true,
-        "14.12.2018 12:34:56 +0200", "14.12.2018 12:34:56");
-  } else {
-    assert.ok(true, "MyFaces 2.3 not activated");
-  }
-});
-
-QUnit.test("OffsetDateTime - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoOffsetDateTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoOffsetDateTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoOffsetDateTimeOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "dd.MM.yyyy HH:mm:ss Z", true, true,
-      "14.12.2018 12:34:56 +0200", "14.12.2018 12:34:56");
-});
-
-QUnit.test("ZonedDateTime - f:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:myfacesZonedDateTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:myfacesZonedDateTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:myfacesZonedDateTimeOutput .tobago-out");
-
-  if (inputFn() !== null) {
-    testConvertDateTime(assert,
-        inputFn, datepickerButtonFn, outputFn,
-        "dd.MM.yyyy HH:mm:ss Z", true, true,
-        "14.12.2018 12:34:56 +0200", "14.12.2018 12:34:56");
-  } else {
-    assert.ok(true, "MyFaces 2.3 not activated");
-  }
-});
-
-QUnit.test("ZonedDateTime - tc:convertDateTime", function (assert) {
-  let inputFn = querySelectorFn("#page\\:mainForm\\:tobagoZonedDateTimeInput\\:\\:field");
-  let datepickerButtonFn = querySelectorFn("#page\\:mainForm\\:tobagoZonedDateTimeInput .datepickerbutton");
-  let outputFn = querySelectorFn("#page\\:mainForm\\:tobagoZonedDateTimeOutput .tobago-out");
-
-  testConvertDateTime(assert,
-      inputFn, datepickerButtonFn, outputFn,
-      "dd.MM.yyyy HH:mm:ss Z", true, true,
-      "14.12.2018 12:34:56 +0200", "14.12.2018 12:34:56");
-});
-
-function testConvertDateTime(assert, inputFn, datepickerButtonFn, outputFn,
-                             expectPattern, expectCalendarIcon, expectClockIcon,
-                             inputValue, expectOutputValue) {
-  let submitButtonFn = querySelectorFn("#page\\:mainForm\\:submitButton");
-
-  let TTT = new TobagoTestTool(assert);
-  TTT.asserts(3, function () {
-    assert.equal(inputFn().dataset.tobagoPattern, expectPattern);
-    assert.equal(datepickerButtonFn().querySelector(".fa-calendar") !== null, expectCalendarIcon);
-    assert.equal(datepickerButtonFn().querySelector(".fa-clock-o") !== null, expectClockIcon);
-  });
-  TTT.action(function () {
-        inputFn().value = inputValue;
-        submitButtonFn().dispatchEvent(new Event("click", {bubbles: true}));
-      }
-  );
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(outputFn().textContent, expectOutputValue);
-  });
-  TTT.startTest();
-}
-*/
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1041-date-tobagoConverter/Date_TobagoConverter.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1041-date-tobagoConverter/Date_TobagoConverter.xhtml
deleted file mode 100644
index ebc299a..0000000
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1041-date-tobagoConverter/Date_TobagoConverter.xhtml
+++ /dev/null
@@ -1,235 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-
-<ui:composition template="/main.xhtml"
-                xmlns="http://www.w3.org/1999/xhtml"
-                xmlns:f="http://xmlns.jcp.org/jsf/core"
-                xmlns:tc="http://myfaces.apache.org/tobago/component"
-                xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
-  <ui:param name="title" value="tc:convertDateTime"/>
-
-  <tc:section label="Date">
-    <tc:segmentLayout extraSmall="6seg">
-      <tc:box label="MyFaces">
-        <tc:date id="myfacesDateInput" label="Date" value="#{convertDateTimeController.myFacesDate}" labelLayout="top">
-          <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss"/>
-        </tc:date>
-        <tc:out id="myfacesDateOutput" label="Output" value="#{convertDateTimeController.myFacesDate}">
-          <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss"/>
-        </tc:out>
-      </tc:box>
-      <tc:box label="Tobago">
-        <tc:date id="tobagoDateInput" label="Date" value="#{convertDateTimeController.tobagoDate}" labelLayout="top">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss"/>
-        </tc:date>
-        <tc:out id="tobagoDateOutput" label="Output" value="#{convertDateTimeController.tobagoDate}">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss"/>
-        </tc:out>
-      </tc:box>
-    </tc:segmentLayout>
-  </tc:section>
-
-  <tc:section label="Calendar">
-    <tc:date id="calendarDate" label="Calendar" value="#{convertDateTimeController.calendar}">
-      <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="calendar"/>
-    </tc:date>
-    <tc:out label="calendarOutput" value="#{convertDateTimeController.calendar}">
-      <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="calendar"/>
-    </tc:out>
-  </tc:section>
-
-  <tc:section label="LocalDate">
-    <tc:segmentLayout extraSmall="6seg">
-      <tc:box label="MyFaces 2.3">
-        <tc:panel rendered="#{version.myfaces and version.version23}">
-          <tc:date id="myfacesLocalDateInput" label="LocalDate" value="#{convertDateTimeController.myFacesLocalDate}"
-                   labelLayout="top">
-            <f:convertDateTime pattern="dd.MM.yyyy" type="localDate"/>
-          </tc:date>
-          <tc:out id="myfacesLocalDateOutput" label="Output" value="#{convertDateTimeController.myFacesLocalDate}">
-            <f:convertDateTime pattern="dd.MM.yyyy" type="localDate"/>
-          </tc:out>
-        </tc:panel>
-        <tc:panel rendered="#{!version.myfaces or !version.version23}">
-          <p>MyFaces 2.3 not activated</p>
-        </tc:panel>
-      </tc:box>
-      <tc:box label="Tobago">
-        <tc:date id="tobagoLocalDateInput" label="LocalDate" value="#{convertDateTimeController.tobagoLocalDate}"
-                 labelLayout="top">
-          <tc:convertDateTime pattern="dd.MM.yyyy" type="localDate"/>
-        </tc:date>
-        <tc:out id="tobagoLocalDateOutput" label="Output" value="#{convertDateTimeController.tobagoLocalDate}">
-          <tc:convertDateTime pattern="dd.MM.yyyy" type="localDate"/>
-        </tc:out>
-      </tc:box>
-    </tc:segmentLayout>
-  </tc:section>
-
-  <tc:section label="LocalTime">
-    <tc:segmentLayout extraSmall="6seg">
-      <tc:box label="MyFaces 2.3">
-        <tc:panel rendered="#{version.myfaces and version.version23}">
-          <tc:date id="myfacesLocalTimeInput" label="LocalTime" value="#{convertDateTimeController.myFacesLocalTime}"
-                   labelLayout="top">
-            <f:convertDateTime pattern="HH:mm:ss" type="localTime"/>
-          </tc:date>
-          <tc:out id="myfacesLocalTimeOutput" label="Output" value="#{convertDateTimeController.myFacesLocalTime}">
-            <f:convertDateTime pattern="HH:mm:ss" type="localTime"/>
-          </tc:out>
-        </tc:panel>
-        <tc:panel rendered="#{!version.myfaces or !version.version23}">
-          <p>MyFaces 2.3 not activated</p>
-        </tc:panel>
-      </tc:box>
-      <tc:box label="Tobago">
-        <tc:date id="tobagoLocalTimeInput" label="LocalTime" value="#{convertDateTimeController.tobagoLocalTime}"
-                 labelLayout="top">
-          <tc:convertDateTime pattern="HH:mm:ss" type="localTime"/>
-        </tc:date>
-        <tc:out id="tobagoLocalTimeOutput" label="Output" value="#{convertDateTimeController.tobagoLocalTime}">
-          <tc:convertDateTime pattern="HH:mm:ss" type="localTime"/>
-        </tc:out>
-      </tc:box>
-    </tc:segmentLayout>
-  </tc:section>
-
-  <tc:section label="LocalDateTime">
-    <tc:segmentLayout extraSmall="6seg">
-      <tc:box label="MyFaces 2.3">
-        <tc:panel rendered="#{version.myfaces and version.version23}">
-          <tc:date id="myfacesLocalDateTimeInput" label="LocalDateTime"
-                   value="#{convertDateTimeController.myFacesLocalDateTime}"
-                   labelLayout="top">
-            <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="localDateTime"/>
-          </tc:date>
-          <tc:out id="myfacesLocalDateTimeOutput" label="Output"
-                  value="#{convertDateTimeController.myFacesLocalDateTime}">
-            <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="localDateTime"/>
-          </tc:out>
-        </tc:panel>
-        <tc:panel rendered="#{!version.myfaces or !version.version23}">
-          <p>MyFaces 2.3 not activated</p>
-        </tc:panel>
-      </tc:box>
-      <tc:box label="Tobago">
-        <tc:date id="tobagoLocalDateTimeInput" label="LocalDateTime"
-                 value="#{convertDateTimeController.tobagoLocalDateTime}"
-                 labelLayout="top">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="localDateTime"/>
-        </tc:date>
-        <tc:out id="tobagoLocalDateTimeOutput" label="Output" value="#{convertDateTimeController.tobagoLocalDateTime}">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="localDateTime"/>
-        </tc:out>
-      </tc:box>
-    </tc:segmentLayout>
-  </tc:section>
-
-  <tc:section label="OffsetTime">
-    <tc:segmentLayout extraSmall="6seg">
-      <tc:box label="MyFaces 2.3">
-        <tc:panel rendered="#{version.myfaces and version.version23}">
-          <tc:date id="myfacesOffsetTimeInput" label="OffsetTime" value="#{convertDateTimeController.myFacesOffsetTime}"
-                   labelLayout="top">
-            <f:convertDateTime pattern="HH:mm:ss Z" type="offsetTime"/>
-          </tc:date>
-          <tc:out id="myfacesOffsetTimeOutput" label="Output" value="#{convertDateTimeController.myFacesOffsetTime}">
-            <f:convertDateTime pattern="HH:mm:ss" type="offsetTime"/>
-          </tc:out>
-        </tc:panel>
-        <tc:panel rendered="#{!version.myfaces or !version.version23}">
-          <p>MyFaces 2.3 not activated</p>
-        </tc:panel>
-      </tc:box>
-      <tc:box label="Tobago">
-        <tc:date id="tobagoOffsetTimeInput" label="OffsetTime" value="#{convertDateTimeController.tobagoOffsetTime}"
-                 labelLayout="top">
-          <tc:convertDateTime pattern="HH:mm:ss Z" type="offsetTime"/>
-        </tc:date>
-        <tc:out id="tobagoOffsetTimeOutput" label="Output" value="#{convertDateTimeController.tobagoOffsetTime}">
-          <tc:convertDateTime pattern="HH:mm:ss" type="offsetTime"/>
-        </tc:out>
-      </tc:box>
-    </tc:segmentLayout>
-  </tc:section>
-
-  <tc:section label="OffsetDateTime">
-    <tc:segmentLayout extraSmall="6seg">
-      <tc:box label="MyFaces 2.3">
-        <tc:panel rendered="#{version.myfaces and version.version23}">
-          <tc:date id="myfacesOffsetDateTimeInput" label="OffsetDateTime"
-                   value="#{convertDateTimeController.myFacesOffsetDateTime}"
-                   labelLayout="top">
-            <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss Z" type="offsetDateTime"/>
-          </tc:date>
-          <tc:out id="myfacesOffsetDateTimeOutput" label="Output"
-                  value="#{convertDateTimeController.myFacesOffsetDateTime}">
-            <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="offsetDateTime"/>
-          </tc:out>
-        </tc:panel>
-        <tc:panel rendered="#{!version.myfaces or !version.version23}">
-          <p>MyFaces 2.3 not activated</p>
-        </tc:panel>
-      </tc:box>
-      <tc:box label="Tobago">
-        <tc:date id="tobagoOffsetDateTimeInput" label="OffsetDateTime"
-                 value="#{convertDateTimeController.tobagoOffsetDateTime}"
-                 labelLayout="top">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss Z" type="offsetDateTime"/>
-        </tc:date>
-        <tc:out id="tobagoOffsetDateTimeOutput" label="Output"
-                value="#{convertDateTimeController.tobagoOffsetDateTime}">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="offsetDateTime"/>
-        </tc:out>
-      </tc:box>
-    </tc:segmentLayout>
-  </tc:section>
-
-  <tc:section label="ZonedDateTime">
-    <tc:segmentLayout extraSmall="6seg">
-      <tc:box label="MyFaces 2.3">
-        <tc:panel rendered="#{version.myfaces and version.version23}">
-          <tc:date id="myfacesZonedDateTimeInput" label="ZonedDateTime"
-                   value="#{convertDateTimeController.myFacesZonedDateTime}"
-                   labelLayout="top">
-            <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss Z" type="zonedDateTime"/>
-          </tc:date>
-          <tc:out id="myfacesZonedDateTimeOutput" label="Output"
-                  value="#{convertDateTimeController.myFacesZonedDateTime}">
-            <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="zonedDateTime"/>
-          </tc:out>
-        </tc:panel>
-        <tc:panel rendered="#{!version.myfaces or !version.version23}">
-          <p>MyFaces 2.3 not activated</p>
-        </tc:panel>
-      </tc:box>
-      <tc:box label="Tobago">
-        <tc:date id="tobagoZonedDateTimeInput" label="ZonedDateTime"
-                 value="#{convertDateTimeController.tobagoZonedDateTime}"
-                 labelLayout="top">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss Z" type="zonedDateTime"/>
-        </tc:date>
-        <tc:out id="tobagoZonedDateTimeOutput" label="Output" value="#{convertDateTimeController.tobagoZonedDateTime}">
-          <tc:convertDateTime pattern="dd.MM.yyyy HH:mm:ss" type="zonedDateTime"/>
-        </tc:out>
-      </tc:box>
-    </tc:segmentLayout>
-  </tc:section>
-
-  <tc:button id="submitButton" label="Submit"/>
-</ui:composition>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1100-date/Date.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1100-date/Date.xhtml
new file mode 100644
index 0000000..99bb008
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/1100-date/Date.xhtml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<ui:composition template="/main.xhtml"
+                xmlns="http://www.w3.org/1999/xhtml"
+                xmlns:tc="http://myfaces.apache.org/tobago/component"
+                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
+                xmlns:f="http://xmlns.jcp.org/jsf/core">
+
+  <tc:segmentLayout large="6seg 6seg" medium="12seg">
+
+    <tc:form>
+      <tc:box label="#1 model=java.time.LocalDate">
+        <tc:date id="localDate" label="LocalDate" value="#{dateTestController.localDate}" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.localDate}"/>
+        <tc:button defaultCommand="true" id="localDateButton" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#2 model=java.time.LocalTime">
+        <tc:date id="localTime" label="LocalTime" value="#{dateTestController.localTime}" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.localTime}"/>
+        <tc:button defaultCommand="true" id="localTimeButton" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#3 model=java.time.LocalTime step=1">
+        <tc:date id="localTimeStepA" label="LocalTime" value="#{dateTestController.localTimeStepA}" step="1" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.localTimeStepA}">
+          <f:convertDateTime pattern="hh:mm:ss" type="localTime"/>
+        </tc:out>
+        <tc:button defaultCommand="true" id="localTimeButtonStepA" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#4 model=java.time.LocalTime step=0.001">
+        <tc:date id="localTimeStepB" label="LocalTime" value="#{dateTestController.localTimeStepB}" step="0.001" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.localTimeStepB}">
+          <f:convertDateTime pattern="hh:mm:ss.SSS" type="localDateTime"/>
+        </tc:out>
+        <tc:button defaultCommand="true" id="localTimeButtonStepB" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#5 model=java.time.LocalDateTime">
+        <tc:date id="localDateTime" label="LocalDateTime" value="#{dateTestController.localDateTime}" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.localDateTime}"/>
+        <tc:button defaultCommand="true" id="localDateTimeButton" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#6 model=java.time.LocalDateTime step=1">
+        <tc:date id="localDateTimeStepA" label="LocalDateTime" value="#{dateTestController.localDateTimeStepA}"
+                 required="true" step="1"/>
+        <tc:out label="Output" value="#{dateTestController.localDateTimeStepA}">
+          <f:convertDateTime pattern="yyyy-MM-dd'T'hh:mm:ss" type="localDateTime"/>
+        </tc:out>
+        <tc:button defaultCommand="true" id="localDateTimeButtonStepA" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#7 model=java.time.LocalDateTime step=0.001">
+        <tc:date id="localDateTimeStepB" label="LocalDateTime" value="#{dateTestController.localDateTimeStepB}"
+                 required="true" step="0.001"/>
+        <tc:out label="Output" value="#{dateTestController.localDateTimeStepB}">
+          <f:convertDateTime pattern="yyyy-MM-dd'T'hh:mm:ss.SSS" type="localDateTime"/>
+        </tc:out>
+        <tc:button defaultCommand="true" id="localDateTimeButtonStepB" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#8 model=java.time.LocalDate type=month">
+        <p>
+          <tc:badge markup="warning" value="Attention:"/>
+          Work in progress.
+        </p>
+        <tc:date id="month" label="Month" value="#{dateTestController.month}" type="month" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.month}"/>
+        <tc:button defaultCommand="true" id="monthButton" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#9 model=java.time.LocalDate type=week">
+        <p>
+          <tc:badge markup="warning" value="Attention:"/>
+          Work in progress.
+        </p>
+        <tc:date id="week" label="Week" value="#{dateTestController.week}" type="week" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.week}"/>
+        <tc:out label="Output" value="#{dateTestController.week}">
+          <f:convertDateTime pattern="yyyy-'W'ww" type="localDateTime"/>
+        </tc:out>
+        <tc:button defaultCommand="true" id="weekButton" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+    <tc:form>
+      <tc:box label="#10 model=java.lang.Long type=date">
+        <p>
+          <tc:badge markup="warning" value="Attention:"/>
+          Work in progress.
+        </p>
+        <tc:date id="long" label="Long" value="#{dateTestController.longValue}" type="date" required="true"/>
+        <tc:out label="Output" value="#{dateTestController.longValue}"/>
+        <tc:button defaultCommand="true" id="longButton" label="Submit"/>
+      </tc:box>
+    </tc:form>
+
+  </tc:segmentLayout>
+
+</ui:composition>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/10-sheet-types/Sheet_Types.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/10-sheet-types/Sheet_Types.xhtml
index 7c49da0..8287260 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/10-sheet-types/Sheet_Types.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/10-sheet-types/Sheet_Types.xhtml
@@ -38,8 +38,9 @@
     <tc:column label="&lt;tc:in>" id="c_in">
       <tc:in value="#{luminary.name}" id="in" labelLayout="skip"/>
     </tc:column>
-    <tc:column label="&lt;tc:date>" id="c_date">
-      <tc:date value="#{luminary.discoverYear}" converter="#{sheetController.yearConverter}" labelLayout="skip"/>
+    <tc:column label="&lt;tc:date> (todo)" id="c_date">
+<!-- todo     <tc:date value="#{luminary.discoverYear}" labelLayout="skip"/>-->
+      <tc:in value="#{luminary.discoverYear}" labelLayout="skip"/>
     </tc:column>
     <tc:column label="&lt;tc:button>" id="c_button">
       <tc:button label="#{luminary.name}"/>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/50000-java/10-rendererBase-getCurrentValue/RendererBase_GetCurrentValue.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/50000-java/10-rendererBase-getCurrentValue/RendererBase_GetCurrentValue.xhtml
index 48694b2..63d7846 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/50000-java/10-rendererBase-getCurrentValue/RendererBase_GetCurrentValue.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/50000-java/10-rendererBase-getCurrentValue/RendererBase_GetCurrentValue.xhtml
@@ -29,12 +29,12 @@
   <tc:out id="outStringFromMethod" labelLayout="none" value="#{currentValueController.toUpperCase('Hello world!')}"/>
 
   <tc:out id="outDate" labelLayout="none" value="#{currentValueController.date}">
-    <f:convertDateTime pattern="dd.MM.yyyy"/>
+    <f:convertDateTime pattern="dd.MM.yyyy" type="localDate"/>
   </tc:out>
 
   <tc:out id="outDateFromMethod" labelLayout="none"
           value="#{currentValueController.plus50(currentValueController.date)}">
-    <f:convertDateTime pattern="dd.MM.yyyy"/>
+    <f:convertDateTime pattern="dd.MM.yyyy" type="localDate"/>
   </tc:out>
 
   <tc:out id="outCurrency" labelLayout="none" value="#{currentValueController.currency}"/>
diff --git a/tobago-theme/package-lock.json b/tobago-theme/package-lock.json
index d87334b..3f8e326 100644
--- a/tobago-theme/package-lock.json
+++ b/tobago-theme/package-lock.json
@@ -5091,11 +5091,6 @@
         "spdx-expression-parse": "^3.0.0"
       }
     },
-    "vanillajs-datepicker": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/vanillajs-datepicker/-/vanillajs-datepicker-1.1.4.tgz",
-      "integrity": "sha512-XJhvRx+VqtRjqrPlgNCQntLpCntFKPMBd8ahxZhLkvrWX0bNdpP3kz5j13L2Q0xfTAY/QMfQtVZvBvRF0NilcA=="
-    },
     "w3c-hr-time": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
diff --git a/tobago-theme/package.json b/tobago-theme/package.json
index 43e834c..06ea901 100644
--- a/tobago-theme/package.json
+++ b/tobago-theme/package.json
@@ -62,8 +62,7 @@
   "dependencies": {
     "@trevoreyre/autocomplete-js": "^2.2.0",
     "bootstrap": "5.1.2",
-    "bootstrap-icons": "1.5.0",
-    "vanillajs-datepicker": "^1.1.4"
+    "bootstrap-icons": "1.5.0"
   },
   "devDependencies": {
     "@popperjs/core": "^2.10.2",
diff --git a/tobago-theme/src/main/scss/datepicker-bs5.scss b/tobago-theme/src/main/scss/datepicker-bs5.scss
deleted file mode 100644
index fca8b19..0000000
--- a/tobago-theme/src/main/scss/datepicker-bs5.scss
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Workaround until the vanilla-datepicker project has their own bs5 CSS.
-
-$dp-background-color: $white !default;
-$dp-border-color: $border-color !default;
-$dp-border-radius: $border-radius !default;
-$dp-border-radius-small: $border-radius-sm !default;
-$dp-line-height-base: 1.5 !default;
-$dp-font-size-normal: $font-size-base !default;
-$dp-font-size-small: $font-size-sm !default;
-$dp-font-weight-semibold: 600 !default;
-$dp-font-weight-bold: $font-weight-bold !default;
-$dp-dropdown-offset: 4px !default;
-$dp-dropdown-shadow: $dropdown-box-shadow !default;
-$dp-dropdown-z: $zindex-dropdown !default;
-
-$dp-title-background-color: $light !default;
-
-$dp-cell-size-base: 2.25rem !default;
-$dp-cell-focus-background-color: darken($dropdown-link-hover-bg, 2.5) !default;
-$dp-cell-prevnext-color: color('gray') !default;
-$dp-cell-disabled-color: $dropdown-link-disabled-color !default;
-$dp-cell-selected-background-color: $dropdown-link-active-bg !default;
-$dp-cell-selected-color: $dropdown-link-active-color !default;
-$dp-cell-selected-font-weight: 600 !default;
-$dp-cell-today-background-color: $teal !default;
-$dp-cell-today-color: $white !default;
-$dp-cell-highlighted-background-color: $gray-100 !default;
-$dp-range-start-end-background-color: $secondary !default;
-$dp-range-start-end-color: $dp-cell-selected-color !default;
-$dp-range-background-color: $gray-200 !default;
-$dp-range-today-background-color: $dp-cell-today-background-color !default;
-$dp-week-color: $gray-300 !default;
-
-$dp-footer-background-color: $light !default;
-
-$dp-input-in-edit-border-color: darken($input-focus-border-color, 5%) !default;
-$dp-input-in-edit-focus-box-shadow-size: 0 0 0.25em 0.25em !default;
-
-// XXX patched because of bs5 begin
-//@import 'mixins';
-@import "node_modules/vanillajs-datepicker/sass/mixins";
-// XXX patched because of bs5 end
-
-@mixin dp-button {
-  .btn {
-    // use custom version of .btn-light
-    $background: $light;
-    $border: $light;
-    $hover-background: darken($background, 7.5%);
-    $hover-border: darken($border, 10%);
-    $active-background: darken($background, 10%);
-    $active-border: darken($border, 12.5%);
-
-    border-color: $border;
-    background-color: $dp-background-color;
-
-    &:hover {
-      border-color: $hover-border;
-      background-color: $hover-background;
-      color: color-contrast($hover-background);
-    }
-
-    &:focus {
-      border-color: $hover-border;
-      box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-contrast($background), $border, 15%), 0.5);
-      background-color: $hover-background;
-      color: color-contrast($hover-background);
-    }
-
-    &:disabled {
-      border-color: $border;
-      background-color: $background;
-      color: color-contrast($background);
-    }
-
-    &:not(:disabled):active {
-      border-color: $active-border;
-      background-color: $active-background;
-      color: color-contrast($active-background);
-
-      &:focus {
-        box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-contrast($background), $border, 15%), 0.5);
-      }
-    }
-
-    .datepicker-header & {
-      @include dp-header-button-common;
-    }
-
-    .datepicker-footer & {
-      @include dp-footer-button-common;
-    }
-  }
-}
-
-// XXX patched because of bs5 begin
-//@import 'datepicker';
-@import "node_modules/vanillajs-datepicker/sass/datepicker";
-// XXX patched because of bs5 end
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css
index 8ff27ab..1b2e540 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css
@@ -11171,257 +11171,6 @@ textarea.form-control-lg {
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-.datepicker {
-  display: none;
-}
-.datepicker.active {
-  display: block;
-}
-
-.datepicker-dropdown {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1000;
-  padding-top: 4px;
-}
-.datepicker-dropdown.datepicker-orient-top {
-  padding-top: 0;
-  padding-bottom: 4px;
-}
-
-.datepicker-picker {
-  display: inline-block;
-  border-radius: 0.25rem;
-  background-color: #ffffff;
-}
-.datepicker-dropdown .datepicker-picker {
-  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
-}
-.datepicker-picker span {
-  display: block;
-  flex: 1;
-  border: 0;
-  border-radius: 0.25rem;
-  cursor: default;
-  text-align: center;
-  -webkit-touch-callout: none;
-  user-select: none;
-}
-
-.datepicker-main {
-  padding: 2px;
-}
-
-.datepicker-footer {
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #ffffff;
-}
-
-.datepicker-grid, .datepicker-view .days-of-week, .datepicker-view, .datepicker-controls {
-  display: flex;
-}
-
-.datepicker-grid {
-  flex-wrap: wrap;
-}
-
-.datepicker-view .days .datepicker-cell, .datepicker-view .dow {
-  flex-basis: 14.2857142857%;
-}
-
-.datepicker-view.datepicker-grid .datepicker-cell {
-  flex-basis: 25%;
-}
-
-.datepicker-cell, .datepicker-view .week {
-  height: 2.25rem;
-  line-height: 2.25rem;
-}
-
-.datepicker-title {
-  box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #ffffff;
-  padding: 0.375rem 0.75rem;
-  text-align: center;
-  font-weight: 700;
-}
-
-.datepicker-header .datepicker-controls {
-  padding: 2px 2px 0;
-}
-.datepicker-controls .btn {
-  border-color: #ffffff;
-  background-color: #ffffff;
-}
-.datepicker-controls .btn:hover {
-  border-color: #e6e6e6;
-  background-color: #ececec;
-  color: #000000;
-}
-.datepicker-controls .btn:focus {
-  border-color: #e6e6e6;
-  box-shadow: 0 0 0 0.25rem rgba(217, 217, 217, 0.5);
-  background-color: #ececec;
-  color: #000000;
-}
-.datepicker-controls .btn:disabled {
-  border-color: #ffffff;
-  background-color: #ffffff;
-  color: #000000;
-}
-.datepicker-controls .btn:not(:disabled):active {
-  border-color: #dfdfdf;
-  background-color: #e6e6e6;
-  color: #000000;
-}
-.datepicker-controls .btn:not(:disabled):active:focus {
-  box-shadow: 0 0 0 0.25rem rgba(217, 217, 217, 0.5);
-}
-.datepicker-header .datepicker-controls .btn {
-  border-color: transparent;
-  font-weight: bold;
-}
-.datepicker-footer .datepicker-controls .btn {
-  margin: calc(0.375rem - 1px) 0.375rem;
-  border-radius: 0.2rem;
-  width: 100%;
-  font-size: 0.875rem;
-}
-.datepicker-controls .view-switch {
-  flex: auto;
-}
-.datepicker-controls .prev-btn,
-.datepicker-controls .next-btn {
-  padding-right: 0.375rem;
-  padding-left: 0.375rem;
-  width: 2.25rem;
-}
-.datepicker-controls .prev-btn.disabled,
-.datepicker-controls .next-btn.disabled {
-  visibility: hidden;
-}
-
-.datepicker-view .dow {
-  height: 1.5rem;
-  line-height: 1.5rem;
-  font-size: 0.9375rem;
-  font-weight: 700;
-}
-.datepicker-view .week {
-  width: 2.25rem;
-  color: #dee2e6;
-  font-size: 0.875rem;
-}
-@media (max-width: 22.5rem) {
-  .datepicker-view .week {
-    width: 1.96875rem;
-  }
-}
-
-.datepicker-grid {
-  width: 15.75rem;
-}
-@media (max-width: 22.5rem) {
-  .calendar-weeks + .days .datepicker-grid {
-    width: 13.78125rem;
-  }
-}
-
-.datepicker-cell:not(.disabled):hover {
-  background-color: #f9f9f9;
-  cursor: pointer;
-}
-.datepicker-cell.focused:not(.selected) {
-  background-color: #cacaca;
-}
-.datepicker-cell.selected, .datepicker-cell.selected:hover {
-  background-color: #529696;
-  color: #abf5ff;
-  font-weight: 600;
-}
-.datepicker-cell.disabled {
-  color: #adb5bd;
-}
-.datepicker-cell.prev:not(.disabled), .datepicker-cell.next:not(.disabled) {
-  color: color("gray");
-}
-.datepicker-cell.prev.selected, .datepicker-cell.next.selected {
-  color: #78efff;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today) {
-  border-radius: 0;
-  background-color: #f8f9fa;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover {
-  background-color: #f1f3f5;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused {
-  background-color: #cacaca;
-}
-.datepicker-cell.today:not(.selected) {
-  background-color: #20c997;
-}
-.datepicker-cell.today:not(.selected):not(.disabled) {
-  color: #ffffff;
-}
-.datepicker-cell.today.focused:not(.selected) {
-  background-color: #1ebe8f;
-}
-.datepicker-cell.range-end:not(.selected), .datepicker-cell.range-start:not(.selected) {
-  background-color: #b2a76d;
-  color: #abf5ff;
-}
-.datepicker-cell.range-end.focused:not(.selected), .datepicker-cell.range-start.focused:not(.selected) {
-  background-color: #aea265;
-}
-.datepicker-cell.range-start {
-  border-radius: 0.25rem 0 0 0.25rem;
-}
-.datepicker-cell.range-end {
-  border-radius: 0 0.25rem 0.25rem 0;
-}
-.datepicker-cell.range {
-  border-radius: 0;
-  background-color: #d0d0d0;
-}
-.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover {
-  background-color: #cacaca;
-}
-.datepicker-cell.range.disabled {
-  color: #b7b7b7;
-}
-.datepicker-cell.range.focused {
-  background-color: #c3c3c3;
-}
-.datepicker-view.datepicker-grid .datepicker-cell {
-  height: 4.5rem;
-  line-height: 4.5rem;
-}
-
-.datepicker-input.in-edit {
-  border-color: #ccc59f;
-}
-.datepicker-input.in-edit:focus, .datepicker-input.in-edit:active {
-  box-shadow: 0 0 0.25em 0.25em rgba(204, 197, 159, 0.2);
-}
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 /* used bootstrap icons ---------------------------------------------------- */
 /* non-bootstrap variables --------------------------------------- */
 /* utilities ----------------------------------------------------- */
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map
index 7624042..6812083 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css
index 22f5094..43ecb96 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#ff00be;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#ffffff;--bs-gray:#777777;--bs-gray-dark:#323232;--bs-gray-100:#f8f9fa;--bs-gray-200:#d0d0d0;--bs-gray-300:#dee2e6;--bs-gray-400:#a0a0a0;--bs-gray-500:#adb5bd;--bs-gray-600:#777777;--bs-gray-700:#495057;--bs-gray-800:#323232;--bs-gray-900:#212529;--bs-primary:#529696;-- [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#ff00be;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#ffffff;--bs-gray:#777777;--bs-gray-dark:#323232;--bs-gray-100:#f8f9fa;--bs-gray-200:#d0d0d0;--bs-gray-300:#dee2e6;--bs-gray-400:#a0a0a0;--bs-gray-500:#adb5bd;--bs-gray-600:#777777;--bs-gray-700:#495057;--bs-gray-800:#323232;--bs-gray-900:#212529;--bs-primary:#529696;-- [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map
index 569b464..60d36a3 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-charlotteville/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,QACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,GAAG,CAAE,IAC3B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,G [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-charlotteville/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,QACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,GAAG,CAAE,IAC3B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,G [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-charlotteville/src/main/scss/tobago-theme.scss b/tobago-theme/tobago-theme-charlotteville/src/main/scss/tobago-theme.scss
index 9a2559b..2ee3300 100644
--- a/tobago-theme/tobago-theme-charlotteville/src/main/scss/tobago-theme.scss
+++ b/tobago-theme/tobago-theme-charlotteville/src/main/scss/tobago-theme.scss
@@ -19,9 +19,4 @@
 
 @import "node_modules/bootstrap/scss/bootstrap";
 
-// XXX patched because of bs5 (begin)
-//@import "node_modules/vanillajs-datepicker/sass/datepicker-bs4";
-@import "../../../../src/main/scss/datepicker-bs5";
-// XXX patched because of bs5 (end)
-
 @import "../../../../src/main/scss/_tobago";
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css
index 6b5646b..2d15e78 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css
@@ -11194,257 +11194,6 @@ textarea.form-control-lg {
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-.datepicker {
-  display: none;
-}
-.datepicker.active {
-  display: block;
-}
-
-.datepicker-dropdown {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1000;
-  padding-top: 4px;
-}
-.datepicker-dropdown.datepicker-orient-top {
-  padding-top: 0;
-  padding-bottom: 4px;
-}
-
-.datepicker-picker {
-  display: inline-block;
-  border-radius: 0.25rem;
-  background-color: #fff;
-}
-.datepicker-dropdown .datepicker-picker {
-  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
-}
-.datepicker-picker span {
-  display: block;
-  flex: 1;
-  border: 0;
-  border-radius: 0.25rem;
-  cursor: default;
-  text-align: center;
-  -webkit-touch-callout: none;
-  user-select: none;
-}
-
-.datepicker-main {
-  padding: 2px;
-}
-
-.datepicker-footer {
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #777777;
-}
-
-.datepicker-grid, .datepicker-view .days-of-week, .datepicker-view, .datepicker-controls {
-  display: flex;
-}
-
-.datepicker-grid {
-  flex-wrap: wrap;
-}
-
-.datepicker-view .days .datepicker-cell, .datepicker-view .dow {
-  flex-basis: 14.2857142857%;
-}
-
-.datepicker-view.datepicker-grid .datepicker-cell {
-  flex-basis: 25%;
-}
-
-.datepicker-cell, .datepicker-view .week {
-  height: 2.25rem;
-  line-height: 2.25rem;
-}
-
-.datepicker-title {
-  box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #777777;
-  padding: 0.375rem 0.75rem;
-  text-align: center;
-  font-weight: 700;
-}
-
-.datepicker-header .datepicker-controls {
-  padding: 2px 2px 0;
-}
-.datepicker-controls .btn {
-  border-color: #777777;
-  background-color: #fff;
-}
-.datepicker-controls .btn:hover {
-  border-color: #5e5e5e;
-  background-color: #646464;
-  color: #fff;
-}
-.datepicker-controls .btn:focus {
-  border-color: #5e5e5e;
-  box-shadow: 0 0 0 0.25rem rgba(101, 101, 101, 0.5);
-  background-color: #646464;
-  color: #fff;
-}
-.datepicker-controls .btn:disabled {
-  border-color: #777777;
-  background-color: #777777;
-  color: #000000;
-}
-.datepicker-controls .btn:not(:disabled):active {
-  border-color: #575757;
-  background-color: #5e5e5e;
-  color: #fff;
-}
-.datepicker-controls .btn:not(:disabled):active:focus {
-  box-shadow: 0 0 0 0.25rem rgba(101, 101, 101, 0.5);
-}
-.datepicker-header .datepicker-controls .btn {
-  border-color: transparent;
-  font-weight: bold;
-}
-.datepicker-footer .datepicker-controls .btn {
-  margin: calc(0.375rem - 1px) 0.375rem;
-  border-radius: 0.2rem;
-  width: 100%;
-  font-size: 0.875rem;
-}
-.datepicker-controls .view-switch {
-  flex: auto;
-}
-.datepicker-controls .prev-btn,
-.datepicker-controls .next-btn {
-  padding-right: 0.375rem;
-  padding-left: 0.375rem;
-  width: 2.25rem;
-}
-.datepicker-controls .prev-btn.disabled,
-.datepicker-controls .next-btn.disabled {
-  visibility: hidden;
-}
-
-.datepicker-view .dow {
-  height: 1.5rem;
-  line-height: 1.5rem;
-  font-size: 0.9375rem;
-  font-weight: 700;
-}
-.datepicker-view .week {
-  width: 2.25rem;
-  color: #dee2e6;
-  font-size: 0.875rem;
-}
-@media (max-width: 22.5rem) {
-  .datepicker-view .week {
-    width: 1.96875rem;
-  }
-}
-
-.datepicker-grid {
-  width: 15.75rem;
-}
-@media (max-width: 22.5rem) {
-  .calendar-weeks + .days .datepicker-grid {
-    width: 13.78125rem;
-  }
-}
-
-.datepicker-cell:not(.disabled):hover {
-  background-color: #f9f9f9;
-  cursor: pointer;
-}
-.datepicker-cell.focused:not(.selected) {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.selected, .datepicker-cell.selected:hover {
-  background-color: #d68200;
-  color: #ffb243;
-  font-weight: 600;
-}
-.datepicker-cell.disabled {
-  color: #adb5bd;
-}
-.datepicker-cell.prev:not(.disabled), .datepicker-cell.next:not(.disabled) {
-  color: color("gray");
-}
-.datepicker-cell.prev.selected, .datepicker-cell.next.selected {
-  color: #ff9d10;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today) {
-  border-radius: 0;
-  background-color: #f8f9fa;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover {
-  background-color: #f1f3f5;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.today:not(.selected) {
-  background-color: #20c997;
-}
-.datepicker-cell.today:not(.selected):not(.disabled) {
-  color: #fff;
-}
-.datepicker-cell.today.focused:not(.selected) {
-  background-color: #1ebe8f;
-}
-.datepicker-cell.range-end:not(.selected), .datepicker-cell.range-start:not(.selected) {
-  background-color: #6c00cb;
-  color: #ffb243;
-}
-.datepicker-cell.range-end.focused:not(.selected), .datepicker-cell.range-start.focused:not(.selected) {
-  background-color: #6500be;
-}
-.datepicker-cell.range-start {
-  border-radius: 0.25rem 0 0 0.25rem;
-}
-.datepicker-cell.range-end {
-  border-radius: 0 0.25rem 0.25rem 0;
-}
-.datepicker-cell.range {
-  border-radius: 0;
-  background-color: #e9ecef;
-}
-.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.range.disabled {
-  color: #cbd3da;
-}
-.datepicker-cell.range.focused {
-  background-color: #dadfe4;
-}
-.datepicker-view.datepicker-grid .datepicker-cell {
-  height: 4.5rem;
-  line-height: 4.5rem;
-}
-
-.datepicker-input.in-edit {
-  border-color: #ffb33d;
-}
-.datepicker-input.in-edit:focus, .datepicker-input.in-edit:active {
-  box-shadow: 0 0 0.25em 0.25em rgba(255, 179, 61, 0.2);
-}
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 /* used bootstrap icons ---------------------------------------------------- */
 /* non-bootstrap variables --------------------------------------- */
 /* utilities ----------------------------------------------------- */
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map
index 888bd35..e593c18 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scs [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css
index 1ea34b0..f195a05 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";@font-face{font-family:Amaranth;font-style:normal;font-weight:400;src:url("../fonts/Amaranth-Regular.otf") format("opentype")}@font-face{font-family:Amaranth;font-style:normal;font-weight:700;src:url("../fonts/Amaranth-Bold.otf") format("opentype")}@font-face{font-family:Amaranth;font-style:italic;src:url("../fonts/Amaranth-Italic.otf") format("opentype")}@font-face{font-family:Amaranth;font-style:italic;font-weight:700;src:url("../fonts/Amaranth-BoldItalic.otf") format( [...]
+@charset "UTF-8";@font-face{font-family:Amaranth;font-style:normal;font-weight:400;src:url("../fonts/Amaranth-Regular.otf") format("opentype")}@font-face{font-family:Amaranth;font-style:normal;font-weight:700;src:url("../fonts/Amaranth-Bold.otf") format("opentype")}@font-face{font-family:Amaranth;font-style:italic;src:url("../fonts/Amaranth-Italic.otf") format("opentype")}@font-face{font-family:Amaranth;font-style:italic;font-weight:700;src:url("../fonts/Amaranth-BoldItalic.otf") format( [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map
index 8586764..9407ab0 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-roxborough/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-roxborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAiCA,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,qCAAqC,mBAE5C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,kCAAkC,mBAEzC,WACE,YAAa,SACb,WAAY,OACZ,IAAK,oCAAoC,mBAE3C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,wCAAwC,mBAEvB,mBAAxB,uBACE,YAAa,QAAQ,CAAE,KAAK,CAAE,MAShC,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB, [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-roxborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAiCA,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,qCAAqC,mBAE5C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,kCAAkC,mBAEzC,WACE,YAAa,SACb,WAAY,OACZ,IAAK,oCAAoC,mBAE3C,WACE,YAAa,SACb,WAAY,OACZ,YAAa,IACb,IAAK,wCAAwC,mBAEvB,mBAAxB,uBACE,YAAa,QAAQ,CAAE,KAAK,CAAE,MAShC,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-roxborough/src/main/scss/tobago-theme.scss b/tobago-theme/tobago-theme-roxborough/src/main/scss/tobago-theme.scss
index 20a8b89..1b8d563 100644
--- a/tobago-theme/tobago-theme-roxborough/src/main/scss/tobago-theme.scss
+++ b/tobago-theme/tobago-theme-roxborough/src/main/scss/tobago-theme.scss
@@ -20,9 +20,4 @@
 
 @import "node_modules/bootstrap/scss/bootstrap";
 
-// XXX patched because of bs5 (begin)
-//@import "node_modules/vanillajs-datepicker/sass/datepicker-bs4";
-@import "../../../../src/main/scss/datepicker-bs5";
-// XXX patched because of bs5 (end)
-
 @import "../../../../src/main/scss/_tobago";
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css
index 211c097..aa8418b 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css
@@ -11135,257 +11135,6 @@ textarea.form-control-lg {
     display: none !important;
   }
 }
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-.datepicker {
-  display: none;
-}
-.datepicker.active {
-  display: block;
-}
-
-.datepicker-dropdown {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1000;
-  padding-top: 4px;
-}
-.datepicker-dropdown.datepicker-orient-top {
-  padding-top: 0;
-  padding-bottom: 4px;
-}
-
-.datepicker-picker {
-  display: inline-block;
-  border-radius: 0.25rem;
-  background-color: #fff;
-}
-.datepicker-dropdown .datepicker-picker {
-  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
-}
-.datepicker-picker span {
-  display: block;
-  flex: 1;
-  border: 0;
-  border-radius: 0.25rem;
-  cursor: default;
-  text-align: center;
-  -webkit-touch-callout: none;
-  user-select: none;
-}
-
-.datepicker-main {
-  padding: 2px;
-}
-
-.datepicker-footer {
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #f8f9fa;
-}
-
-.datepicker-grid, .datepicker-view .days-of-week, .datepicker-view, .datepicker-controls {
-  display: flex;
-}
-
-.datepicker-grid {
-  flex-wrap: wrap;
-}
-
-.datepicker-view .days .datepicker-cell, .datepicker-view .dow {
-  flex-basis: 14.2857142857%;
-}
-
-.datepicker-view.datepicker-grid .datepicker-cell {
-  flex-basis: 25%;
-}
-
-.datepicker-cell, .datepicker-view .week {
-  height: 2.25rem;
-  line-height: 2.25rem;
-}
-
-.datepicker-title {
-  box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #f8f9fa;
-  padding: 0.375rem 0.75rem;
-  text-align: center;
-  font-weight: 700;
-}
-
-.datepicker-header .datepicker-controls {
-  padding: 2px 2px 0;
-}
-.datepicker-controls .btn {
-  border-color: #f8f9fa;
-  background-color: #fff;
-}
-.datepicker-controls .btn:hover {
-  border-color: #dae0e5;
-  background-color: #e2e6ea;
-  color: #000;
-}
-.datepicker-controls .btn:focus {
-  border-color: #dae0e5;
-  box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);
-  background-color: #e2e6ea;
-  color: #000;
-}
-.datepicker-controls .btn:disabled {
-  border-color: #f8f9fa;
-  background-color: #f8f9fa;
-  color: #000;
-}
-.datepicker-controls .btn:not(:disabled):active {
-  border-color: #d3d9df;
-  background-color: #dae0e5;
-  color: #000;
-}
-.datepicker-controls .btn:not(:disabled):active:focus {
-  box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);
-}
-.datepicker-header .datepicker-controls .btn {
-  border-color: transparent;
-  font-weight: bold;
-}
-.datepicker-footer .datepicker-controls .btn {
-  margin: calc(0.375rem - 1px) 0.375rem;
-  border-radius: 0.2rem;
-  width: 100%;
-  font-size: 0.875rem;
-}
-.datepicker-controls .view-switch {
-  flex: auto;
-}
-.datepicker-controls .prev-btn,
-.datepicker-controls .next-btn {
-  padding-right: 0.375rem;
-  padding-left: 0.375rem;
-  width: 2.25rem;
-}
-.datepicker-controls .prev-btn.disabled,
-.datepicker-controls .next-btn.disabled {
-  visibility: hidden;
-}
-
-.datepicker-view .dow {
-  height: 1.5rem;
-  line-height: 1.5rem;
-  font-size: 0.9375rem;
-  font-weight: 700;
-}
-.datepicker-view .week {
-  width: 2.25rem;
-  color: #dee2e6;
-  font-size: 0.875rem;
-}
-@media (max-width: 22.5rem) {
-  .datepicker-view .week {
-    width: 1.96875rem;
-  }
-}
-
-.datepicker-grid {
-  width: 15.75rem;
-}
-@media (max-width: 22.5rem) {
-  .calendar-weeks + .days .datepicker-grid {
-    width: 13.78125rem;
-  }
-}
-
-.datepicker-cell:not(.disabled):hover {
-  background-color: #f9f9f9;
-  cursor: pointer;
-}
-.datepicker-cell.focused:not(.selected) {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.selected, .datepicker-cell.selected:hover {
-  background-color: #0d6efd;
-  color: #fff;
-  font-weight: 600;
-}
-.datepicker-cell.disabled {
-  color: #adb5bd;
-}
-.datepicker-cell.prev:not(.disabled), .datepicker-cell.next:not(.disabled) {
-  color: color("gray");
-}
-.datepicker-cell.prev.selected, .datepicker-cell.next.selected {
-  color: #e6e6e6;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today) {
-  border-radius: 0;
-  background-color: #f8f9fa;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover {
-  background-color: #f1f3f5;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.today:not(.selected) {
-  background-color: #20c997;
-}
-.datepicker-cell.today:not(.selected):not(.disabled) {
-  color: #fff;
-}
-.datepicker-cell.today.focused:not(.selected) {
-  background-color: #1ebe8f;
-}
-.datepicker-cell.range-end:not(.selected), .datepicker-cell.range-start:not(.selected) {
-  background-color: #6c757d;
-  color: #fff;
-}
-.datepicker-cell.range-end.focused:not(.selected), .datepicker-cell.range-start.focused:not(.selected) {
-  background-color: #666f76;
-}
-.datepicker-cell.range-start {
-  border-radius: 0.25rem 0 0 0.25rem;
-}
-.datepicker-cell.range-end {
-  border-radius: 0 0.25rem 0.25rem 0;
-}
-.datepicker-cell.range {
-  border-radius: 0;
-  background-color: #e9ecef;
-}
-.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.range.disabled {
-  color: #cbd3da;
-}
-.datepicker-cell.range.focused {
-  background-color: #dadfe4;
-}
-.datepicker-view.datepicker-grid .datepicker-cell {
-  height: 4.5rem;
-  line-height: 4.5rem;
-}
-
-.datepicker-input.in-edit {
-  border-color: #6da8fe;
-}
-.datepicker-input.in-edit:focus, .datepicker-input.in-edit:active {
-  box-shadow: 0 0 0.25em 0.25em rgba(109, 168, 254, 0.2);
-}
-
 .btn-secondary {
   color: #000;
   background-color: #fff;
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map
index c16d7e0..caf9d3a 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css
index 1c4b162..d36657b 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs- [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs- [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map
index d65b580..c660d48 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-scarborough/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-scarborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,GAAG,CAAE,IAC3B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,EAAE [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-scarborough/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,GAAG,CAAE,IAC3B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,EAAE [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-scarborough/src/main/scss/tobago-theme.scss b/tobago-theme/tobago-theme-scarborough/src/main/scss/tobago-theme.scss
index 6a1e080..86fe0c9 100644
--- a/tobago-theme/tobago-theme-scarborough/src/main/scss/tobago-theme.scss
+++ b/tobago-theme/tobago-theme-scarborough/src/main/scss/tobago-theme.scss
@@ -17,11 +17,6 @@
 
 @import "node_modules/bootstrap/scss/bootstrap";
 
-// XXX patched because of bs5 (begin)
-//@import "node_modules/vanillajs-datepicker/sass/datepicker-bs4";
-@import "../../../../src/main/scss/datepicker-bs5";
-// XXX patched because of bs5 (end)
-
 .btn-secondary {
   @include button-variant($white, $gray-400);
 }
diff --git a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css
index 9d336c3..292eeb2 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css
@@ -10881,257 +10881,6 @@ textarea.form-control-lg {
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-.datepicker {
-  display: none;
-}
-.datepicker.active {
-  display: block;
-}
-
-.datepicker-dropdown {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1000;
-  padding-top: 4px;
-}
-.datepicker-dropdown.datepicker-orient-top {
-  padding-top: 0;
-  padding-bottom: 4px;
-}
-
-.datepicker-picker {
-  display: inline-block;
-  border-radius: 0.25rem;
-  background-color: #fff;
-}
-.datepicker-dropdown .datepicker-picker {
-  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
-}
-.datepicker-picker span {
-  display: block;
-  flex: 1;
-  border: 0;
-  border-radius: 0.25rem;
-  cursor: default;
-  text-align: center;
-  -webkit-touch-callout: none;
-  user-select: none;
-}
-
-.datepicker-main {
-  padding: 2px;
-}
-
-.datepicker-footer {
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #f7f7f7;
-}
-
-.datepicker-grid, .datepicker-view .days-of-week, .datepicker-view, .datepicker-controls {
-  display: flex;
-}
-
-.datepicker-grid {
-  flex-wrap: wrap;
-}
-
-.datepicker-view .days .datepicker-cell, .datepicker-view .dow {
-  flex-basis: 14.2857142857%;
-}
-
-.datepicker-view.datepicker-grid .datepicker-cell {
-  flex-basis: 25%;
-}
-
-.datepicker-cell, .datepicker-view .week {
-  height: 2.25rem;
-  line-height: 2.25rem;
-}
-
-.datepicker-title {
-  box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #f7f7f7;
-  padding: 0.375rem 0.75rem;
-  text-align: center;
-  font-weight: 700;
-}
-
-.datepicker-header .datepicker-controls {
-  padding: 2px 2px 0;
-}
-.datepicker-controls .btn {
-  border-color: #f7f7f7;
-  background-color: #fff;
-}
-.datepicker-controls .btn:hover {
-  border-color: #dedede;
-  background-color: #e4e4e4;
-  color: #000;
-}
-.datepicker-controls .btn:focus {
-  border-color: #dedede;
-  box-shadow: 0 0 0 0.25rem rgba(210, 210, 210, 0.5);
-  background-color: #e4e4e4;
-  color: #000;
-}
-.datepicker-controls .btn:disabled {
-  border-color: #f7f7f7;
-  background-color: #f7f7f7;
-  color: #000;
-}
-.datepicker-controls .btn:not(:disabled):active {
-  border-color: #d7d7d7;
-  background-color: #dedede;
-  color: #000;
-}
-.datepicker-controls .btn:not(:disabled):active:focus {
-  box-shadow: 0 0 0 0.25rem rgba(210, 210, 210, 0.5);
-}
-.datepicker-header .datepicker-controls .btn {
-  border-color: transparent;
-  font-weight: bold;
-}
-.datepicker-footer .datepicker-controls .btn {
-  margin: calc(0.375rem - 1px) 0.375rem;
-  border-radius: 0.2rem;
-  width: 100%;
-  font-size: 0.875rem;
-}
-.datepicker-controls .view-switch {
-  flex: auto;
-}
-.datepicker-controls .prev-btn,
-.datepicker-controls .next-btn {
-  padding-right: 0.375rem;
-  padding-left: 0.375rem;
-  width: 2.25rem;
-}
-.datepicker-controls .prev-btn.disabled,
-.datepicker-controls .next-btn.disabled {
-  visibility: hidden;
-}
-
-.datepicker-view .dow {
-  height: 1.5rem;
-  line-height: 1.5rem;
-  font-size: 0.9375rem;
-  font-weight: 700;
-}
-.datepicker-view .week {
-  width: 2.25rem;
-  color: #d7d7d7;
-  font-size: 0.875rem;
-}
-@media (max-width: 22.5rem) {
-  .datepicker-view .week {
-    width: 1.96875rem;
-  }
-}
-
-.datepicker-grid {
-  width: 15.75rem;
-}
-@media (max-width: 22.5rem) {
-  .calendar-weeks + .days .datepicker-grid {
-    width: 13.78125rem;
-  }
-}
-
-.datepicker-cell:not(.disabled):hover {
-  background-color: #f9f9f9;
-  cursor: pointer;
-}
-.datepicker-cell.focused:not(.selected) {
-  background-color: #dcdedf;
-}
-.datepicker-cell.selected, .datepicker-cell.selected:hover {
-  background-color: #a36725;
-  color: #fff;
-  font-weight: 600;
-}
-.datepicker-cell.disabled {
-  color: #acacac;
-}
-.datepicker-cell.prev:not(.disabled), .datepicker-cell.next:not(.disabled) {
-  color: color("gray");
-}
-.datepicker-cell.prev.selected, .datepicker-cell.next.selected {
-  color: #e6e6e6;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today) {
-  border-radius: 0;
-  background-color: #f7f7f7;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover {
-  background-color: #f1f1f1;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused {
-  background-color: #dcdedf;
-}
-.datepicker-cell.today:not(.selected) {
-  background-color: #20c997;
-}
-.datepicker-cell.today:not(.selected):not(.disabled) {
-  color: #fff;
-}
-.datepicker-cell.today.focused:not(.selected) {
-  background-color: #1ebe8f;
-}
-.datepicker-cell.range-end:not(.selected), .datepicker-cell.range-start:not(.selected) {
-  background-color: #d7d7d7;
-  color: #fff;
-}
-.datepicker-cell.range-end.focused:not(.selected), .datepicker-cell.range-start.focused:not(.selected) {
-  background-color: #d1d1d1;
-}
-.datepicker-cell.range-start {
-  border-radius: 0.25rem 0 0 0.25rem;
-}
-.datepicker-cell.range-end {
-  border-radius: 0 0.25rem 0.25rem 0;
-}
-.datepicker-cell.range {
-  border-radius: 0;
-  background-color: #e3e4e5;
-}
-.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover {
-  background-color: #dcdedf;
-}
-.datepicker-cell.range.disabled {
-  color: #c9cbcc;
-}
-.datepicker-cell.range.focused {
-  background-color: #d6d7d9;
-}
-.datepicker-view.datepicker-grid .datepicker-cell {
-  height: 4.5rem;
-  line-height: 4.5rem;
-}
-
-.datepicker-input.in-edit {
-  border-color: #7da083;
-}
-.datepicker-input.in-edit:focus, .datepicker-input.in-edit:active {
-  box-shadow: 0 0 0.25em 0.25em rgba(125, 160, 131, 0.2);
-}
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 /* used bootstrap icons ---------------------------------------------------- */
 /* non-bootstrap variables --------------------------------------- */
 /* utilities ----------------------------------------------------- */
diff --git a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map
index 6ec129d..78ff406 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_modules/bootstrap/scss/mixins/_lists.scss","../. [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../scss/_custom.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_modules/bootstrap/scss/mixins/_lists.scss","../. [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css
index 9ef2796..af5254e 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#3a2564;--bs-pink:#d63384;--bs-red:#d30040;--bs-orange:#d90;--bs-yellow:#ffc107;--bs-green:#1da332;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#788c94;--bs-gray-dark:#323232;--bs-gray-100:#f7f7f7;--bs-gray-200:#e3e4e5;--bs-gray-300:#d7d7d7;--bs-gray-400:#ced4da;--bs-gray-500:#acacac;--bs-gray-600:#788c94;--bs-gray-700:#55595c;--bs-gray-800:#323232;--bs-gray-900:#212529;--bs-primary:#185722;--bs-sec [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#3a2564;--bs-pink:#d63384;--bs-red:#d30040;--bs-orange:#d90;--bs-yellow:#ffc107;--bs-green:#1da332;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#788c94;--bs-gray-dark:#323232;--bs-gray-100:#f7f7f7;--bs-gray-200:#e3e4e5;--bs-gray-300:#d7d7d7;--bs-gray-400:#ced4da;--bs-gray-500:#acacac;--bs-gray-600:#788c94;--bs-gray-700:#55595c;--bs-gray-800:#323232;--bs-gray-900:#212529;--bs-primary:#185722;--bs-sec [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map
index 7909b08..ac9d5ec 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-speyside/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-speyside/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,KACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,EAAE,CAAE,GAC1B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,EAAE,CA [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-speyside/src/main/css/tobago.css"],"names":[],"mappings":"iBAuCA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,KACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,EAAE,CAAE,GAC1B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,EAAE,CA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-speyside/src/main/scss/tobago-theme.scss b/tobago-theme/tobago-theme-speyside/src/main/scss/tobago-theme.scss
index 54e2075..b7af707 100644
--- a/tobago-theme/tobago-theme-speyside/src/main/scss/tobago-theme.scss
+++ b/tobago-theme/tobago-theme-speyside/src/main/scss/tobago-theme.scss
@@ -20,11 +20,6 @@
 
 @import "node_modules/bootstrap/scss/bootstrap";
 
-// XXX patched because of bs5 (begin)
-//@import "node_modules/vanillajs-datepicker/sass/datepicker-bs4";
-@import "../../../../src/main/scss/datepicker-bs5";
-// XXX patched because of bs5 (end)
-
 @import "../../../../src/main/scss/_tobago";
 
 @import "speyside-classes";
diff --git a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css
index 7eec6bc..80a749d 100644
--- a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css
+++ b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css
@@ -11151,257 +11151,6 @@ textarea.form-control-lg {
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-.datepicker {
-  display: none;
-}
-.datepicker.active {
-  display: block;
-}
-
-.datepicker-dropdown {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 1000;
-  padding-top: 4px;
-}
-.datepicker-dropdown.datepicker-orient-top {
-  padding-top: 0;
-  padding-bottom: 4px;
-}
-
-.datepicker-picker {
-  display: inline-block;
-  border-radius: 0.25rem;
-  background-color: #fff;
-}
-.datepicker-dropdown .datepicker-picker {
-  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
-}
-.datepicker-picker span {
-  display: block;
-  flex: 1;
-  border: 0;
-  border-radius: 0.25rem;
-  cursor: default;
-  text-align: center;
-  -webkit-touch-callout: none;
-  user-select: none;
-}
-
-.datepicker-main {
-  padding: 2px;
-}
-
-.datepicker-footer {
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #f8f9fa;
-}
-
-.datepicker-grid, .datepicker-view .days-of-week, .datepicker-view, .datepicker-controls {
-  display: flex;
-}
-
-.datepicker-grid {
-  flex-wrap: wrap;
-}
-
-.datepicker-view .days .datepicker-cell, .datepicker-view .dow {
-  flex-basis: 14.2857142857%;
-}
-
-.datepicker-view.datepicker-grid .datepicker-cell {
-  flex-basis: 25%;
-}
-
-.datepicker-cell, .datepicker-view .week {
-  height: 2.25rem;
-  line-height: 2.25rem;
-}
-
-.datepicker-title {
-  box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.1);
-  background-color: #f8f9fa;
-  padding: 0.375rem 0.75rem;
-  text-align: center;
-  font-weight: 700;
-}
-
-.datepicker-header .datepicker-controls {
-  padding: 2px 2px 0;
-}
-.datepicker-controls .btn {
-  border-color: #f8f9fa;
-  background-color: #fff;
-}
-.datepicker-controls .btn:hover {
-  border-color: #dae0e5;
-  background-color: #e2e6ea;
-  color: #000;
-}
-.datepicker-controls .btn:focus {
-  border-color: #dae0e5;
-  box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);
-  background-color: #e2e6ea;
-  color: #000;
-}
-.datepicker-controls .btn:disabled {
-  border-color: #f8f9fa;
-  background-color: #f8f9fa;
-  color: #000;
-}
-.datepicker-controls .btn:not(:disabled):active {
-  border-color: #d3d9df;
-  background-color: #dae0e5;
-  color: #000;
-}
-.datepicker-controls .btn:not(:disabled):active:focus {
-  box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);
-}
-.datepicker-header .datepicker-controls .btn {
-  border-color: transparent;
-  font-weight: bold;
-}
-.datepicker-footer .datepicker-controls .btn {
-  margin: calc(0.375rem - 1px) 0.375rem;
-  border-radius: 0.2rem;
-  width: 100%;
-  font-size: 0.875rem;
-}
-.datepicker-controls .view-switch {
-  flex: auto;
-}
-.datepicker-controls .prev-btn,
-.datepicker-controls .next-btn {
-  padding-right: 0.375rem;
-  padding-left: 0.375rem;
-  width: 2.25rem;
-}
-.datepicker-controls .prev-btn.disabled,
-.datepicker-controls .next-btn.disabled {
-  visibility: hidden;
-}
-
-.datepicker-view .dow {
-  height: 1.5rem;
-  line-height: 1.5rem;
-  font-size: 0.9375rem;
-  font-weight: 700;
-}
-.datepicker-view .week {
-  width: 2.25rem;
-  color: #dee2e6;
-  font-size: 0.875rem;
-}
-@media (max-width: 22.5rem) {
-  .datepicker-view .week {
-    width: 1.96875rem;
-  }
-}
-
-.datepicker-grid {
-  width: 15.75rem;
-}
-@media (max-width: 22.5rem) {
-  .calendar-weeks + .days .datepicker-grid {
-    width: 13.78125rem;
-  }
-}
-
-.datepicker-cell:not(.disabled):hover {
-  background-color: #f9f9f9;
-  cursor: pointer;
-}
-.datepicker-cell.focused:not(.selected) {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.selected, .datepicker-cell.selected:hover {
-  background-color: #0d6efd;
-  color: #fff;
-  font-weight: 600;
-}
-.datepicker-cell.disabled {
-  color: #adb5bd;
-}
-.datepicker-cell.prev:not(.disabled), .datepicker-cell.next:not(.disabled) {
-  color: color("gray");
-}
-.datepicker-cell.prev.selected, .datepicker-cell.next.selected {
-  color: #e6e6e6;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today) {
-  border-radius: 0;
-  background-color: #f8f9fa;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover {
-  background-color: #f1f3f5;
-}
-.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.today:not(.selected) {
-  background-color: #20c997;
-}
-.datepicker-cell.today:not(.selected):not(.disabled) {
-  color: #fff;
-}
-.datepicker-cell.today.focused:not(.selected) {
-  background-color: #1ebe8f;
-}
-.datepicker-cell.range-end:not(.selected), .datepicker-cell.range-start:not(.selected) {
-  background-color: #6c757d;
-  color: #fff;
-}
-.datepicker-cell.range-end.focused:not(.selected), .datepicker-cell.range-start.focused:not(.selected) {
-  background-color: #666f76;
-}
-.datepicker-cell.range-start {
-  border-radius: 0.25rem 0 0 0.25rem;
-}
-.datepicker-cell.range-end {
-  border-radius: 0 0.25rem 0.25rem 0;
-}
-.datepicker-cell.range {
-  border-radius: 0;
-  background-color: #e9ecef;
-}
-.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover {
-  background-color: #e2e6ea;
-}
-.datepicker-cell.range.disabled {
-  color: #cbd3da;
-}
-.datepicker-cell.range.focused {
-  background-color: #dadfe4;
-}
-.datepicker-view.datepicker-grid .datepicker-cell {
-  height: 4.5rem;
-  line-height: 4.5rem;
-}
-
-.datepicker-input.in-edit {
-  border-color: #6da8fe;
-}
-.datepicker-input.in-edit:focus, .datepicker-input.in-edit:active {
-  box-shadow: 0 0 0.25em 0.25em rgba(109, 168, 254, 0.2);
-}
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 /* used bootstrap icons ---------------------------------------------------- */
 /* non-bootstrap variables --------------------------------------- */
 /* utilities ----------------------------------------------------- */
diff --git a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map
index 14b5c68..a643e38 100644
--- a/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map
+++ b/tobago-theme/tobago-theme-standard/src/main/css/tobago.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../scss/tobago-theme.scss","../../../../node_modules/bootstrap/scss/bootstrap.scss","../../../../node_modules/bootstrap/scss/_root.scss","../../../../node_modules/bootstrap/scss/_reboot.scss","../../../../node_modules/bootstrap/scss/vendor/_rfs.scss","../../../../node_modules/bootstrap/scss/_variables.scss","../../../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../../../node_modules/bootstrap/scss/_type.scss","../../../../node_mo [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css b/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css
index aa509ea..0e52689 100644
--- a/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css
+++ b/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css
@@ -1,2 +1,2 @@
-@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs- [...]
+@charset "UTF-8";:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs- [...]
 /*# sourceMappingURL=tobago.min.css.map */
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map b/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map
index ce5db72..4fcac1b 100644
--- a/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map
+++ b/tobago-theme/tobago-theme-standard/src/main/css/tobago.min.css.map
@@ -1 +1 @@
-{"version":3,"sources":["tobago-theme-standard/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,GAAG,CAAE,IAC3B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,EAAE,CA [...]
\ No newline at end of file
+{"version":3,"sources":["tobago-theme-standard/src/main/css/tobago.css"],"names":[],"mappings":"iBAuBA,MACE,UAAW,QACX,YAAa,QACb,YAAa,QACb,UAAW,QACX,SAAU,QACV,YAAa,QACb,YAAa,QACb,WAAY,QACZ,UAAW,QACX,UAAW,QACX,WAAY,KACZ,UAAW,QACX,eAAgB,QAChB,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,cAAe,QACf,aAAc,QACd,eAAgB,QAChB,aAAc,QACd,UAAW,QACX,aAAc,QACd,YAAa,QACb,WAAY,QACZ,UAAW,QACX,iBAAkB,EAAE,CAAE,GAAG,CAAE,IAC3B,mBAAoB,GAAG,CAAE,GAAG,CAAE,IAC9B,iBAAkB,EAAE,CA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
index 77c4567..54fbbda 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
@@ -7560,2549 +7560,6 @@
       }
   });
 
-  function hasProperty(obj, prop) {
-    return Object.prototype.hasOwnProperty.call(obj, prop);
-  }
-
-  function lastItemOf(arr) {
-    return arr[arr.length - 1];
-  }
-
-  // push only the items not included in the array
-  function pushUnique(arr, ...items) {
-    items.forEach((item) => {
-      if (arr.includes(item)) {
-        return;
-      }
-      arr.push(item);
-    });
-    return arr;
-  }
-
-  function stringToArray(str, separator) {
-    // convert empty string to an empty array
-    return str ? str.split(separator) : [];
-  }
-
-  function isInRange(testVal, min, max) {
-    const minOK = min === undefined || testVal >= min;
-    const maxOK = max === undefined || testVal <= max;
-    return minOK && maxOK;
-  }
-
-  function limitToRange(val, min, max) {
-    if (val < min) {
-      return min;
-    }
-    if (val > max) {
-      return max;
-    }
-    return val;
-  }
-
-  function createTagRepeat(tagName, repeat, attributes = {}, index = 0, html = '') {
-    const openTagSrc = Object.keys(attributes).reduce((src, attr) => {
-      let val = attributes[attr];
-      if (typeof val === 'function') {
-        val = val(index);
-      }
-      return `${src} ${attr}="${val}"`;
-    }, tagName);
-    html += `<${openTagSrc}></${tagName}>`;
-
-    const next = index + 1;
-    return next < repeat
-      ? createTagRepeat(tagName, repeat, attributes, next, html)
-      : html;
-  }
-
-  // Remove the spacing surrounding tags for HTML parser not to create text nodes
-  // before/after elements
-  function optimizeTemplateHTML(html) {
-    return html.replace(/>\s+/g, '>').replace(/\s+</, '<');
-  }
-
-  function stripTime(timeValue) {
-    return new Date(timeValue).setHours(0, 0, 0, 0);
-  }
-
-  function today() {
-    return new Date().setHours(0, 0, 0, 0);
-  }
-
-  // Get the time value of the start of given date or year, month and day
-  function dateValue(...args) {
-    switch (args.length) {
-      case 0:
-        return today();
-      case 1:
-        return stripTime(args[0]);
-    }
-
-    // use setFullYear() to keep 2-digit year from being mapped to 1900-1999
-    const newDate = new Date(0);
-    newDate.setFullYear(...args);
-    return newDate.setHours(0, 0, 0, 0);
-  }
-
-  function addDays(date, amount) {
-    const newDate = new Date(date);
-    return newDate.setDate(newDate.getDate() + amount);
-  }
-
-  function addWeeks(date, amount) {
-    return addDays(date, amount * 7);
-  }
-
-  function addMonths(date, amount) {
-    // If the day of the date is not in the new month, the last day of the new
-    // month will be returned. e.g. Jan 31 + 1 month → Feb 28 (not Mar 03)
-    const newDate = new Date(date);
-    const monthsToSet = newDate.getMonth() + amount;
-    let expectedMonth = monthsToSet % 12;
-    if (expectedMonth < 0) {
-      expectedMonth += 12;
-    }
-
-    const time = newDate.setMonth(monthsToSet);
-    return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time;
-  }
-
-  function addYears(date, amount) {
-    // If the date is Feb 29 and the new year is not a leap year, Feb 28 of the
-    // new year will be returned.
-    const newDate = new Date(date);
-    const expectedMonth = newDate.getMonth();
-    const time = newDate.setFullYear(newDate.getFullYear() + amount);
-    return expectedMonth === 1 && newDate.getMonth() === 2 ? newDate.setDate(0) : time;
-  }
-
-  // Calculate the distance bettwen 2 days of the week
-  function dayDiff(day, from) {
-    return (day - from + 7) % 7;
-  }
-
-  // Get the date of the specified day of the week of given base date
-  function dayOfTheWeekOf(baseDate, dayOfWeek, weekStart = 0) {
-    const baseDay = new Date(baseDate).getDay();
-    return addDays(baseDate, dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart));
-  }
-
-  // Get the ISO week of a date
-  function getWeek(date) {
-    // start of ISO week is Monday
-    const thuOfTheWeek = dayOfTheWeekOf(date, 4, 1);
-    // 1st week == the week where the 4th of January is in
-    const firstThu = dayOfTheWeekOf(new Date(thuOfTheWeek).setMonth(0, 4), 4, 1);
-    return Math.round((thuOfTheWeek - firstThu) / 604800000) + 1;
-  }
-
-  // Get the start year of the period of years that includes given date
-  // years: length of the year period
-  function startOfYearPeriod(date, years) {
-    /* @see https://en.wikipedia.org/wiki/Year_zero#ISO_8601 */
-    const year = new Date(date).getFullYear();
-    return Math.floor(year / years) * years;
-  }
-
-  // pattern for format parts
-  const reFormatTokens = /dd?|DD?|mm?|MM?|yy?(?:yy)?/;
-  // pattern for non date parts
-  const reNonDateParts = /[\s!-/:-@[-`{-~年月日]+/;
-  // cache for persed formats
-  let knownFormats = {};
-  // parse funtions for date parts
-  const parseFns = {
-    y(date, year) {
-      return new Date(date).setFullYear(parseInt(year, 10));
-    },
-    m(date, month, locale) {
-      const newDate = new Date(date);
-      let monthIndex = parseInt(month, 10) - 1;
-
-      if (isNaN(monthIndex)) {
-        if (!month) {
-          return NaN;
-        }
-
-        const monthName = month.toLowerCase();
-        const compareNames = name => name.toLowerCase().startsWith(monthName);
-        // compare with both short and full names because some locales have periods
-        // in the short names (not equal to the first X letters of the full names)
-        monthIndex = locale.monthsShort.findIndex(compareNames);
-        if (monthIndex < 0) {
-          monthIndex = locale.months.findIndex(compareNames);
-        }
-        if (monthIndex < 0) {
-          return NaN;
-        }
-      }
-
-      newDate.setMonth(monthIndex);
-      return newDate.getMonth() !== normalizeMonth(monthIndex)
-        ? newDate.setDate(0)
-        : newDate.getTime();
-    },
-    d(date, day) {
-      return new Date(date).setDate(parseInt(day, 10));
-    },
-  };
-  // format functions for date parts
-  const formatFns = {
-    d(date) {
-      return date.getDate();
-    },
-    dd(date) {
-      return padZero(date.getDate(), 2);
-    },
-    D(date, locale) {
-      return locale.daysShort[date.getDay()];
-    },
-    DD(date, locale) {
-      return locale.days[date.getDay()];
-    },
-    m(date) {
-      return date.getMonth() + 1;
-    },
-    mm(date) {
-      return padZero(date.getMonth() + 1, 2);
-    },
-    M(date, locale) {
-      return locale.monthsShort[date.getMonth()];
-    },
-    MM(date, locale) {
-      return locale.months[date.getMonth()];
-    },
-    y(date) {
-      return date.getFullYear();
-    },
-    yy(date) {
-      return padZero(date.getFullYear(), 2).slice(-2);
-    },
-    yyyy(date) {
-      return padZero(date.getFullYear(), 4);
-    },
-  };
-
-  // get month index in normal range (0 - 11) from any number
-  function normalizeMonth(monthIndex) {
-    return monthIndex > -1 ? monthIndex % 12 : normalizeMonth(monthIndex + 12);
-  }
-
-  function padZero(num, length) {
-    return num.toString().padStart(length, '0');
-  }
-
-  function parseFormatString(format) {
-    if (typeof format !== 'string') {
-      throw new Error("Invalid date format.");
-    }
-    if (format in knownFormats) {
-      return knownFormats[format];
-    }
-
-    // sprit the format string into parts and seprators
-    const separators = format.split(reFormatTokens);
-    const parts = format.match(new RegExp(reFormatTokens, 'g'));
-    if (separators.length === 0 || !parts) {
-      throw new Error("Invalid date format.");
-    }
-
-    // collect format functions used in the format
-    const partFormatters = parts.map(token => formatFns[token]);
-
-    // collect parse function keys used in the format
-    // iterate over parseFns' keys in order to keep the order of the keys.
-    const partParserKeys = Object.keys(parseFns).reduce((keys, key) => {
-      const token = parts.find(part => part[0] !== 'D' && part[0].toLowerCase() === key);
-      if (token) {
-        keys.push(key);
-      }
-      return keys;
-    }, []);
-
-    return knownFormats[format] = {
-      parser(dateStr, locale) {
-        const dateParts = dateStr.split(reNonDateParts).reduce((dtParts, part, index) => {
-          if (part.length > 0 && parts[index]) {
-            const token = parts[index][0];
-            if (token === 'M') {
-              dtParts.m = part;
-            } else if (token !== 'D') {
-              dtParts[token] = part;
-            }
-          }
-          return dtParts;
-        }, {});
-
-        // iterate over partParserkeys so that the parsing is made in the oder
-        // of year, month and day to prevent the day parser from correcting last
-        // day of month wrongly
-        return partParserKeys.reduce((origDate, key) => {
-          const newDate = parseFns[key](origDate, dateParts[key], locale);
-          // ingnore the part failed to parse
-          return isNaN(newDate) ? origDate : newDate;
-        }, today());
-      },
-      formatter(date, locale) {
-        let dateStr = partFormatters.reduce((str, fn, index) => {
-          return str += `${separators[index]}${fn(date, locale)}`;
-        }, '');
-        // separators' length is always parts' length + 1,
-        return dateStr += lastItemOf(separators);
-      },
-    };
-  }
-
-  function parseDate(dateStr, format, locale) {
-    if (dateStr instanceof Date || typeof dateStr === 'number') {
-      const date = stripTime(dateStr);
-      return isNaN(date) ? undefined : date;
-    }
-    if (!dateStr) {
-      return undefined;
-    }
-    if (dateStr === 'today') {
-      return today();
-    }
-
-    if (format && format.toValue) {
-      const date = format.toValue(dateStr, format, locale);
-      return isNaN(date) ? undefined : stripTime(date);
-    }
-
-    return parseFormatString(format).parser(dateStr, locale);
-  }
-
-  function formatDate(date, format, locale) {
-    if (isNaN(date) || (!date && date !== 0)) {
-      return '';
-    }
-
-    const dateObj = typeof date === 'number' ? new Date(date) : date;
-
-    if (format.toDisplay) {
-      return format.toDisplay(dateObj, format, locale);
-    }
-
-    return parseFormatString(format).formatter(dateObj, locale);
-  }
-
-  const listenerRegistry = new WeakMap();
-  const {addEventListener, removeEventListener} = EventTarget.prototype;
-
-  // Register event listeners to a key object
-  // listeners: array of listener definitions;
-  //   - each definition must be a flat array of event target and the arguments
-  //     used to call addEventListener() on the target
-  function registerListeners(keyObj, listeners) {
-    let registered = listenerRegistry.get(keyObj);
-    if (!registered) {
-      registered = [];
-      listenerRegistry.set(keyObj, registered);
-    }
-    listeners.forEach((listener) => {
-      addEventListener.call(...listener);
-      registered.push(listener);
-    });
-  }
-
-  function unregisterListeners(keyObj) {
-    let listeners = listenerRegistry.get(keyObj);
-    if (!listeners) {
-      return;
-    }
-    listeners.forEach((listener) => {
-      removeEventListener.call(...listener);
-    });
-    listenerRegistry.delete(keyObj);
-  }
-
-  // Event.composedPath() polyfill for Edge
-  // based on https://gist.github.com/kleinfreund/e9787d73776c0e3750dcfcdc89f100ec
-  if (!Event.prototype.composedPath) {
-    const getComposedPath = (node, path = []) => {
-      path.push(node);
-
-      let parent;
-      if (node.parentNode) {
-        parent = node.parentNode;
-      } else if (node.host) { // ShadowRoot
-        parent = node.host;
-      } else if (node.defaultView) {  // Document
-        parent = node.defaultView;
-      }
-      return parent ? getComposedPath(parent, path) : path;
-    };
-
-    Event.prototype.composedPath = function () {
-      return getComposedPath(this.target);
-    };
-  }
-
-  function findFromPath(path, criteria, currentTarget, index = 0) {
-    const el = path[index];
-    if (criteria(el)) {
-      return el;
-    } else if (el === currentTarget || !el.parentElement) {
-      // stop when reaching currentTarget or <html>
-      return;
-    }
-    return findFromPath(path, criteria, currentTarget, index + 1);
-  }
-
-  // Search for the actual target of a delegated event
-  function findElementInEventPath(ev, selector) {
-    const criteria = typeof selector === 'function' ? selector : el => el.matches(selector);
-    return findFromPath(ev.composedPath(), criteria, ev.currentTarget);
-  }
-
-  // default locales
-  const locales = {
-    en: {
-      days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
-      daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
-      daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
-      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"],
-      today: "Today",
-      clear: "Clear",
-      titleFormat: "MM y"
-    }
-  };
-
-  // config options updatable by setOptions() and their default values
-  const defaultOptions = {
-    autohide: false,
-    beforeShowDay: null,
-    beforeShowDecade: null,
-    beforeShowMonth: null,
-    beforeShowYear: null,
-    calendarWeeks: false,
-    clearBtn: false,
-    dateDelimiter: ',',
-    datesDisabled: [],
-    daysOfWeekDisabled: [],
-    daysOfWeekHighlighted: [],
-    defaultViewDate: undefined, // placeholder, defaults to today() by the program
-    disableTouchKeyboard: false,
-    format: 'mm/dd/yyyy',
-    language: 'en',
-    maxDate: null,
-    maxNumberOfDates: 1,
-    maxView: 3,
-    minDate: null,
-    nextArrow: '»',
-    orientation: 'auto',
-    pickLevel: 0,
-    prevArrow: '«',
-    showDaysOfWeek: true,
-    showOnClick: true,
-    showOnFocus: true,
-    startView: 0,
-    title: '',
-    todayBtn: false,
-    todayBtnMode: 0,
-    todayHighlight: false,
-    updateOnBlur: true,
-    weekStart: 0,
-  };
-
-  const range = document.createRange();
-
-  function parseHTML(html) {
-    return range.createContextualFragment(html);
-  }
-
-  function hideElement(el) {
-    if (el.style.display === 'none') {
-      return;
-    }
-    // back up the existing display setting in data-style-display
-    if (el.style.display) {
-      el.dataset.styleDisplay = el.style.display;
-    }
-    el.style.display = 'none';
-  }
-
-  function showElement(el) {
-    if (el.style.display !== 'none') {
-      return;
-    }
-    if (el.dataset.styleDisplay) {
-      // restore backed-up dispay property
-      el.style.display = el.dataset.styleDisplay;
-      delete el.dataset.styleDisplay;
-    } else {
-      el.style.display = '';
-    }
-  }
-
-  function emptyChildNodes(el) {
-    if (el.firstChild) {
-      el.removeChild(el.firstChild);
-      emptyChildNodes(el);
-    }
-  }
-
-  function replaceChildNodes(el, newChildNodes) {
-    emptyChildNodes(el);
-    if (newChildNodes instanceof DocumentFragment) {
-      el.appendChild(newChildNodes);
-    } else if (typeof newChildNodes === 'string') {
-      el.appendChild(parseHTML(newChildNodes));
-    } else if (typeof newChildNodes.forEach === 'function') {
-      newChildNodes.forEach((node) => {
-        el.appendChild(node);
-      });
-    }
-  }
-
-  const {
-    language: defaultLang,
-    format: defaultFormat,
-    weekStart: defaultWeekStart,
-  } = defaultOptions;
-
-  // Reducer function to filter out invalid day-of-week from the input
-  function sanitizeDOW(dow, day) {
-    return dow.length < 6 && day >= 0 && day < 7
-      ? pushUnique(dow, day)
-      : dow;
-  }
-
-  function calcEndOfWeek(startOfWeek) {
-    return (startOfWeek + 6) % 7;
-  }
-
-  // validate input date. if invalid, fallback to the original value
-  function validateDate(value, format, locale, origValue) {
-    const date = parseDate(value, format, locale);
-    return date !== undefined ? date : origValue;
-  }
-
-  // Validate viewId. if invalid, fallback to the original value
-  function validateViewId(value, origValue, max = 3) {
-    const viewId = parseInt(value, 10);
-    return viewId >= 0 && viewId <= max ? viewId : origValue;
-  }
-
-  // Create Datepicker configuration to set
-  function processOptions(options, datepicker) {
-    const inOpts = Object.assign({}, options);
-    const config = {};
-    const locales = datepicker.constructor.locales;
-    let {
-      format,
-      language,
-      locale,
-      maxDate,
-      maxView,
-      minDate,
-      pickLevel,
-      startView,
-      weekStart,
-    } = datepicker.config || {};
-
-    if (inOpts.language) {
-      let lang;
-      if (inOpts.language !== language) {
-        if (locales[inOpts.language]) {
-          lang = inOpts.language;
-        } else {
-          // Check if langauge + region tag can fallback to the one without
-          // region (e.g. fr-CA → fr)
-          lang = inOpts.language.split('-')[0];
-          if (locales[lang] === undefined) {
-            lang = false;
-          }
-        }
-      }
-      delete inOpts.language;
-      if (lang) {
-        language = config.language = lang;
-
-        // update locale as well when updating language
-        const origLocale = locale || locales[defaultLang];
-        // use default language's properties for the fallback
-        locale = Object.assign({
-          format: defaultFormat,
-          weekStart: defaultWeekStart
-        }, locales[defaultLang]);
-        if (language !== defaultLang) {
-          Object.assign(locale, locales[language]);
-        }
-        config.locale = locale;
-        // if format and/or weekStart are the same as old locale's defaults,
-        // update them to new locale's defaults
-        if (format === origLocale.format) {
-          format = config.format = locale.format;
-        }
-        if (weekStart === origLocale.weekStart) {
-          weekStart = config.weekStart = locale.weekStart;
-          config.weekEnd = calcEndOfWeek(locale.weekStart);
-        }
-      }
-    }
-
-    if (inOpts.format) {
-      const hasToDisplay = typeof inOpts.format.toDisplay === 'function';
-      const hasToValue = typeof inOpts.format.toValue === 'function';
-      const validFormatString = reFormatTokens.test(inOpts.format);
-      if ((hasToDisplay && hasToValue) || validFormatString) {
-        format = config.format = inOpts.format;
-      }
-      delete inOpts.format;
-    }
-
-    //*** dates ***//
-    // while min and maxDate for "no limit" in the options are better to be null
-    // (especially when updating), the ones in the config have to be undefined
-    // because null is treated as 0 (= unix epoch) when comparing with time value
-    let minDt = minDate;
-    let maxDt = maxDate;
-    if (inOpts.minDate !== undefined) {
-      minDt = inOpts.minDate === null
-        ? dateValue(0, 0, 1)  // set 0000-01-01 to prevent negative values for year
-        : validateDate(inOpts.minDate, format, locale, minDt);
-      delete inOpts.minDate;
-    }
-    if (inOpts.maxDate !== undefined) {
-      maxDt = inOpts.maxDate === null
-        ? undefined
-        : validateDate(inOpts.maxDate, format, locale, maxDt);
-      delete inOpts.maxDate;
-    }
-    if (maxDt < minDt) {
-      minDate = config.minDate = maxDt;
-      maxDate = config.maxDate = minDt;
-    } else {
-      if (minDate !== minDt) {
-        minDate = config.minDate = minDt;
-      }
-      if (maxDate !== maxDt) {
-        maxDate = config.maxDate = maxDt;
-      }
-    }
-
-    if (inOpts.datesDisabled) {
-      config.datesDisabled = inOpts.datesDisabled.reduce((dates, dt) => {
-        const date = parseDate(dt, format, locale);
-        return date !== undefined ? pushUnique(dates, date) : dates;
-      }, []);
-      delete inOpts.datesDisabled;
-    }
-    if (inOpts.defaultViewDate !== undefined) {
-      const viewDate = parseDate(inOpts.defaultViewDate, format, locale);
-      if (viewDate !== undefined) {
-        config.defaultViewDate = viewDate;
-      }
-      delete inOpts.defaultViewDate;
-    }
-
-    //*** days of week ***//
-    if (inOpts.weekStart !== undefined) {
-      const wkStart = Number(inOpts.weekStart) % 7;
-      if (!isNaN(wkStart)) {
-        weekStart = config.weekStart = wkStart;
-        config.weekEnd = calcEndOfWeek(wkStart);
-      }
-      delete inOpts.weekStart;
-    }
-    if (inOpts.daysOfWeekDisabled) {
-      config.daysOfWeekDisabled = inOpts.daysOfWeekDisabled.reduce(sanitizeDOW, []);
-      delete inOpts.daysOfWeekDisabled;
-    }
-    if (inOpts.daysOfWeekHighlighted) {
-      config.daysOfWeekHighlighted = inOpts.daysOfWeekHighlighted.reduce(sanitizeDOW, []);
-      delete inOpts.daysOfWeekHighlighted;
-    }
-
-    //*** multi date ***//
-    if (inOpts.maxNumberOfDates !== undefined) {
-      const maxNumberOfDates = parseInt(inOpts.maxNumberOfDates, 10);
-      if (maxNumberOfDates >= 0) {
-        config.maxNumberOfDates = maxNumberOfDates;
-        config.multidate = maxNumberOfDates !== 1;
-      }
-      delete inOpts.maxNumberOfDates;
-    }
-    if (inOpts.dateDelimiter) {
-      config.dateDelimiter = String(inOpts.dateDelimiter);
-      delete inOpts.dateDelimiter;
-    }
-
-    //*** pick level & view ***//
-    let newPickLevel = pickLevel;
-    if (inOpts.pickLevel !== undefined) {
-      newPickLevel = validateViewId(inOpts.pickLevel, 2);
-      delete inOpts.pickLevel;
-    }
-    if (newPickLevel !== pickLevel) {
-      pickLevel = config.pickLevel = newPickLevel;
-    }
-
-    let newMaxView = maxView;
-    if (inOpts.maxView !== undefined) {
-      newMaxView = validateViewId(inOpts.maxView, maxView);
-      delete inOpts.maxView;
-    }
-    // ensure max view >= pick level
-    newMaxView = pickLevel > newMaxView ? pickLevel : newMaxView;
-    if (newMaxView !== maxView) {
-      maxView = config.maxView = newMaxView;
-    }
-
-    let newStartView = startView;
-    if (inOpts.startView !== undefined) {
-      newStartView = validateViewId(inOpts.startView, newStartView);
-      delete inOpts.startView;
-    }
-    // ensure pick level <= start view <= max view
-    if (newStartView < pickLevel) {
-      newStartView = pickLevel;
-    } else if (newStartView > maxView) {
-      newStartView = maxView;
-    }
-    if (newStartView !== startView) {
-      config.startView = newStartView;
-    }
-
-    //*** template ***//
-    if (inOpts.prevArrow) {
-      const prevArrow = parseHTML(inOpts.prevArrow);
-      if (prevArrow.childNodes.length > 0) {
-        config.prevArrow = prevArrow.childNodes;
-      }
-      delete inOpts.prevArrow;
-    }
-    if (inOpts.nextArrow) {
-      const nextArrow = parseHTML(inOpts.nextArrow);
-      if (nextArrow.childNodes.length > 0) {
-        config.nextArrow = nextArrow.childNodes;
-      }
-      delete inOpts.nextArrow;
-    }
-
-    //*** misc ***//
-    if (inOpts.disableTouchKeyboard !== undefined) {
-      config.disableTouchKeyboard = 'ontouchstart' in document && !!inOpts.disableTouchKeyboard;
-      delete inOpts.disableTouchKeyboard;
-    }
-    if (inOpts.orientation) {
-      const orientation = inOpts.orientation.toLowerCase().split(/\s+/g);
-      config.orientation = {
-        x: orientation.find(x => (x === 'left' || x === 'right')) || 'auto',
-        y: orientation.find(y => (y === 'top' || y === 'bottom')) || 'auto',
-      };
-      delete inOpts.orientation;
-    }
-    if (inOpts.todayBtnMode !== undefined) {
-      switch(inOpts.todayBtnMode) {
-        case 0:
-        case 1:
-          config.todayBtnMode = inOpts.todayBtnMode;
-      }
-      delete inOpts.todayBtnMode;
-    }
-
-    //*** copy the rest ***//
-    Object.keys(inOpts).forEach((key) => {
-      if (inOpts[key] !== undefined && hasProperty(defaultOptions, key)) {
-        config[key] = inOpts[key];
-      }
-    });
-
-    return config;
-  }
-
-  const pickerTemplate = optimizeTemplateHTML(`<div class="datepicker">
-  <div class="datepicker-picker">
-    <div class="datepicker-header">
-      <div class="datepicker-title"></div>
-      <div class="datepicker-controls">
-        <button type="button" class="%buttonClass% prev-btn"></button>
-        <button type="button" class="%buttonClass% view-switch"></button>
-        <button type="button" class="%buttonClass% next-btn"></button>
-      </div>
-    </div>
-    <div class="datepicker-main"></div>
-    <div class="datepicker-footer">
-      <div class="datepicker-controls">
-        <button type="button" class="%buttonClass% today-btn"></button>
-        <button type="button" class="%buttonClass% clear-btn"></button>
-      </div>
-    </div>
-  </div>
-</div>`);
-
-  const daysTemplate = optimizeTemplateHTML(`<div class="days">
-  <div class="days-of-week">${createTagRepeat('span', 7, {class: 'dow'})}</div>
-  <div class="datepicker-grid">${createTagRepeat('span', 42)}</div>
-</div>`);
-
-  const calendarWeeksTemplate = optimizeTemplateHTML(`<div class="calendar-weeks">
-  <div class="days-of-week"><span class="dow"></span></div>
-  <div class="weeks">${createTagRepeat('span', 6, {class: 'week'})}</div>
-</div>`);
-
-  // Base class of the view classes
-  class View {
-    constructor(picker, config) {
-      Object.assign(this, config, {
-        picker,
-        element: parseHTML(`<div class="datepicker-view"></div>`).firstChild,
-        selected: [],
-      });
-      this.init(this.picker.datepicker.config);
-    }
-
-    init(options) {
-      if (options.pickLevel !== undefined) {
-        this.isMinView = this.id === options.pickLevel;
-      }
-      this.setOptions(options);
-      this.updateFocus();
-      this.updateSelection();
-    }
-
-    // Execute beforeShow() callback and apply the result to the element
-    // args:
-    // - current - current value on the iteration on view rendering
-    // - timeValue - time value of the date to pass to beforeShow()
-    performBeforeHook(el, current, timeValue) {
-      let result = this.beforeShow(new Date(timeValue));
-      switch (typeof result) {
-        case 'boolean':
-          result = {enabled: result};
-          break;
-        case 'string':
-          result = {classes: result};
-      }
-
-      if (result) {
-        if (result.enabled === false) {
-          el.classList.add('disabled');
-          pushUnique(this.disabled, current);
-        }
-        if (result.classes) {
-          const extraClasses = result.classes.split(/\s+/);
-          el.classList.add(...extraClasses);
-          if (extraClasses.includes('disabled')) {
-            pushUnique(this.disabled, current);
-          }
-        }
-        if (result.content) {
-          replaceChildNodes(el, result.content);
-        }
-      }
-    }
-  }
-
-  class DaysView extends View {
-    constructor(picker) {
-      super(picker, {
-        id: 0,
-        name: 'days',
-        cellClass: 'day',
-      });
-    }
-
-    init(options, onConstruction = true) {
-      if (onConstruction) {
-        const inner = parseHTML(daysTemplate).firstChild;
-        this.dow = inner.firstChild;
-        this.grid = inner.lastChild;
-        this.element.appendChild(inner);
-      }
-      super.init(options);
-    }
-
-    setOptions(options) {
-      let updateDOW;
-
-      if (hasProperty(options, 'minDate')) {
-        this.minDate = options.minDate;
-      }
-      if (hasProperty(options, 'maxDate')) {
-        this.maxDate = options.maxDate;
-      }
-      if (options.datesDisabled) {
-        this.datesDisabled = options.datesDisabled;
-      }
-      if (options.daysOfWeekDisabled) {
-        this.daysOfWeekDisabled = options.daysOfWeekDisabled;
-        updateDOW = true;
-      }
-      if (options.daysOfWeekHighlighted) {
-        this.daysOfWeekHighlighted = options.daysOfWeekHighlighted;
-      }
-      if (options.todayHighlight !== undefined) {
-        this.todayHighlight = options.todayHighlight;
-      }
-      if (options.weekStart !== undefined) {
-        this.weekStart = options.weekStart;
-        this.weekEnd = options.weekEnd;
-        updateDOW = true;
-      }
-      if (options.locale) {
-        const locale = this.locale = options.locale;
-        this.dayNames = locale.daysMin;
-        this.switchLabelFormat = locale.titleFormat;
-        updateDOW = true;
-      }
-      if (options.beforeShowDay !== undefined) {
-        this.beforeShow = typeof options.beforeShowDay === 'function'
-          ? options.beforeShowDay
-          : undefined;
-      }
-
-      if (options.calendarWeeks !== undefined) {
-        if (options.calendarWeeks && !this.calendarWeeks) {
-          const weeksElem = parseHTML(calendarWeeksTemplate).firstChild;
-          this.calendarWeeks = {
-            element: weeksElem,
-            dow: weeksElem.firstChild,
-            weeks: weeksElem.lastChild,
-          };
-          this.element.insertBefore(weeksElem, this.element.firstChild);
-        } else if (this.calendarWeeks && !options.calendarWeeks) {
-          this.element.removeChild(this.calendarWeeks.element);
-          this.calendarWeeks = null;
-        }
-      }
-      if (options.showDaysOfWeek !== undefined) {
-        if (options.showDaysOfWeek) {
-          showElement(this.dow);
-          if (this.calendarWeeks) {
-            showElement(this.calendarWeeks.dow);
-          }
-        } else {
-          hideElement(this.dow);
-          if (this.calendarWeeks) {
-            hideElement(this.calendarWeeks.dow);
-          }
-        }
-      }
-
-      // update days-of-week when locale, daysOfweekDisabled or weekStart is changed
-      if (updateDOW) {
-        Array.from(this.dow.children).forEach((el, index) => {
-          const dow = (this.weekStart + index) % 7;
-          el.textContent = this.dayNames[dow];
-          el.className = this.daysOfWeekDisabled.includes(dow) ? 'dow disabled' : 'dow';
-        });
-      }
-    }
-
-    // Apply update on the focused date to view's settings
-    updateFocus() {
-      const viewDate = new Date(this.picker.viewDate);
-      const viewYear = viewDate.getFullYear();
-      const viewMonth = viewDate.getMonth();
-      const firstOfMonth = dateValue(viewYear, viewMonth, 1);
-      const start = dayOfTheWeekOf(firstOfMonth, this.weekStart, this.weekStart);
-
-      this.first = firstOfMonth;
-      this.last = dateValue(viewYear, viewMonth + 1, 0);
-      this.start = start;
-      this.focused = this.picker.viewDate;
-    }
-
-    // Apply update on the selected dates to view's settings
-    updateSelection() {
-      const {dates, rangepicker} = this.picker.datepicker;
-      this.selected = dates;
-      if (rangepicker) {
-        this.range = rangepicker.dates;
-      }
-    }
-
-     // Update the entire view UI
-    render() {
-      // update today marker on ever render
-      this.today = this.todayHighlight ? today() : undefined;
-      // refresh disabled dates on every render in order to clear the ones added
-      // by beforeShow hook at previous render
-      this.disabled = [...this.datesDisabled];
-
-      const switchLabel = formatDate(this.focused, this.switchLabelFormat, this.locale);
-      this.picker.setViewSwitchLabel(switchLabel);
-      this.picker.setPrevBtnDisabled(this.first <= this.minDate);
-      this.picker.setNextBtnDisabled(this.last >= this.maxDate);
-
-      if (this.calendarWeeks) {
-        // start of the UTC week (Monday) of the 1st of the month
-        const startOfWeek = dayOfTheWeekOf(this.first, 1, 1);
-        Array.from(this.calendarWeeks.weeks.children).forEach((el, index) => {
-          el.textContent = getWeek(addWeeks(startOfWeek, index));
-        });
-      }
-      Array.from(this.grid.children).forEach((el, index) => {
-        const classList = el.classList;
-        const current = addDays(this.start, index);
-        const date = new Date(current);
-        const day = date.getDay();
-
-        el.className = `datepicker-cell ${this.cellClass}`;
-        el.dataset.date = current;
-        el.textContent = date.getDate();
-
-        if (current < this.first) {
-          classList.add('prev');
-        } else if (current > this.last) {
-          classList.add('next');
-        }
-        if (this.today === current) {
-          classList.add('today');
-        }
-        if (current < this.minDate || current > this.maxDate || this.disabled.includes(current)) {
-          classList.add('disabled');
-        }
-        if (this.daysOfWeekDisabled.includes(day)) {
-          classList.add('disabled');
-          pushUnique(this.disabled, current);
-        }
-        if (this.daysOfWeekHighlighted.includes(day)) {
-          classList.add('highlighted');
-        }
-        if (this.range) {
-          const [rangeStart, rangeEnd] = this.range;
-          if (current > rangeStart && current < rangeEnd) {
-            classList.add('range');
-          }
-          if (current === rangeStart) {
-            classList.add('range-start');
-          }
-          if (current === rangeEnd) {
-            classList.add('range-end');
-          }
-        }
-        if (this.selected.includes(current)) {
-          classList.add('selected');
-        }
-        if (current === this.focused) {
-          classList.add('focused');
-        }
-
-        if (this.beforeShow) {
-          this.performBeforeHook(el, current, current);
-        }
-      });
-    }
-
-    // Update the view UI by applying the changes of selected and focused items
-    refresh() {
-      const [rangeStart, rangeEnd] = this.range || [];
-      this.grid
-        .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
-        .forEach((el) => {
-          el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
-        });
-      Array.from(this.grid.children).forEach((el) => {
-        const current = Number(el.dataset.date);
-        const classList = el.classList;
-        if (current > rangeStart && current < rangeEnd) {
-          classList.add('range');
-        }
-        if (current === rangeStart) {
-          classList.add('range-start');
-        }
-        if (current === rangeEnd) {
-          classList.add('range-end');
-        }
-        if (this.selected.includes(current)) {
-          classList.add('selected');
-        }
-        if (current === this.focused) {
-          classList.add('focused');
-        }
-      });
-    }
-
-    // Update the view UI by applying the change of focused item
-    refreshFocus() {
-      const index = Math.round((this.focused - this.start) / 86400000);
-      this.grid.querySelectorAll('.focused').forEach((el) => {
-        el.classList.remove('focused');
-      });
-      this.grid.children[index].classList.add('focused');
-    }
-  }
-
-  function computeMonthRange(range, thisYear) {
-    if (!range || !range[0] || !range[1]) {
-      return;
-    }
-
-    const [[startY, startM], [endY, endM]] = range;
-    if (startY > thisYear || endY < thisYear) {
-      return;
-    }
-    return [
-      startY === thisYear ? startM : -1,
-      endY === thisYear ? endM : 12,
-    ];
-  }
-
-  class MonthsView extends View {
-    constructor(picker) {
-      super(picker, {
-        id: 1,
-        name: 'months',
-        cellClass: 'month',
-      });
-    }
-
-    init(options, onConstruction = true) {
-      if (onConstruction) {
-        this.grid = this.element;
-        this.element.classList.add('months', 'datepicker-grid');
-        this.grid.appendChild(parseHTML(createTagRepeat('span', 12, {'data-month': ix => ix})));
-      }
-      super.init(options);
-    }
-
-    setOptions(options) {
-      if (options.locale) {
-        this.monthNames = options.locale.monthsShort;
-      }
-      if (hasProperty(options, 'minDate')) {
-        if (options.minDate === undefined) {
-          this.minYear = this.minMonth = this.minDate = undefined;
-        } else {
-          const minDateObj = new Date(options.minDate);
-          this.minYear = minDateObj.getFullYear();
-          this.minMonth = minDateObj.getMonth();
-          this.minDate = minDateObj.setDate(1);
-        }
-      }
-      if (hasProperty(options, 'maxDate')) {
-        if (options.maxDate === undefined) {
-          this.maxYear = this.maxMonth = this.maxDate = undefined;
-        } else {
-          const maxDateObj = new Date(options.maxDate);
-          this.maxYear = maxDateObj.getFullYear();
-          this.maxMonth = maxDateObj.getMonth();
-          this.maxDate = dateValue(this.maxYear, this.maxMonth + 1, 0);
-        }
-      }
-      if (options.beforeShowMonth !== undefined) {
-        this.beforeShow = typeof options.beforeShowMonth === 'function'
-          ? options.beforeShowMonth
-          : undefined;
-      }
-    }
-
-    // Update view's settings to reflect the viewDate set on the picker
-    updateFocus() {
-      const viewDate = new Date(this.picker.viewDate);
-      this.year = viewDate.getFullYear();
-      this.focused = viewDate.getMonth();
-    }
-
-    // Update view's settings to reflect the selected dates
-    updateSelection() {
-      const {dates, rangepicker} = this.picker.datepicker;
-      this.selected = dates.reduce((selected, timeValue) => {
-        const date = new Date(timeValue);
-        const year = date.getFullYear();
-        const month = date.getMonth();
-        if (selected[year] === undefined) {
-          selected[year] = [month];
-        } else {
-          pushUnique(selected[year], month);
-        }
-        return selected;
-      }, {});
-      if (rangepicker && rangepicker.dates) {
-        this.range = rangepicker.dates.map(timeValue => {
-          const date = new Date(timeValue);
-          return isNaN(date) ? undefined : [date.getFullYear(), date.getMonth()];
-        });
-      }
-    }
-
-    // Update the entire view UI
-    render() {
-      // refresh disabled months on every render in order to clear the ones added
-      // by beforeShow hook at previous render
-      this.disabled = [];
-
-      this.picker.setViewSwitchLabel(this.year);
-      this.picker.setPrevBtnDisabled(this.year <= this.minYear);
-      this.picker.setNextBtnDisabled(this.year >= this.maxYear);
-
-      const selected = this.selected[this.year] || [];
-      const yrOutOfRange = this.year < this.minYear || this.year > this.maxYear;
-      const isMinYear = this.year === this.minYear;
-      const isMaxYear = this.year === this.maxYear;
-      const range = computeMonthRange(this.range, this.year);
-
-      Array.from(this.grid.children).forEach((el, index) => {
-        const classList = el.classList;
-        const date = dateValue(this.year, index, 1);
-
-        el.className = `datepicker-cell ${this.cellClass}`;
-        if (this.isMinView) {
-          el.dataset.date = date;
-        }
-        // reset text on every render to clear the custom content set
-        // by beforeShow hook at previous render
-        el.textContent = this.monthNames[index];
-
-        if (
-          yrOutOfRange
-          || isMinYear && index < this.minMonth
-          || isMaxYear && index > this.maxMonth
-        ) {
-          classList.add('disabled');
-        }
-        if (range) {
-          const [rangeStart, rangeEnd] = range;
-          if (index > rangeStart && index < rangeEnd) {
-            classList.add('range');
-          }
-          if (index === rangeStart) {
-            classList.add('range-start');
-          }
-          if (index === rangeEnd) {
-            classList.add('range-end');
-          }
-        }
-        if (selected.includes(index)) {
-          classList.add('selected');
-        }
-        if (index === this.focused) {
-          classList.add('focused');
-        }
-
-        if (this.beforeShow) {
-          this.performBeforeHook(el, index, date);
-        }
-      });
-    }
-
-    // Update the view UI by applying the changes of selected and focused items
-    refresh() {
-      const selected = this.selected[this.year] || [];
-      const [rangeStart, rangeEnd] = computeMonthRange(this.range, this.year) || [];
-      this.grid
-        .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
-        .forEach((el) => {
-          el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
-        });
-      Array.from(this.grid.children).forEach((el, index) => {
-        const classList = el.classList;
-        if (index > rangeStart && index < rangeEnd) {
-          classList.add('range');
-        }
-        if (index === rangeStart) {
-          classList.add('range-start');
-        }
-        if (index === rangeEnd) {
-          classList.add('range-end');
-        }
-        if (selected.includes(index)) {
-          classList.add('selected');
-        }
-        if (index === this.focused) {
-          classList.add('focused');
-        }
-      });
-    }
-
-    // Update the view UI by applying the change of focused item
-    refreshFocus() {
-      this.grid.querySelectorAll('.focused').forEach((el) => {
-        el.classList.remove('focused');
-      });
-      this.grid.children[this.focused].classList.add('focused');
-    }
-  }
-
-  function toTitleCase(word) {
-    return [...word].reduce((str, ch, ix) => str += ix ? ch : ch.toUpperCase(), '');
-  }
-
-  // Class representing the years and decades view elements
-  class YearsView extends View {
-    constructor(picker, config) {
-      super(picker, config);
-    }
-
-    init(options, onConstruction = true) {
-      if (onConstruction) {
-        this.navStep = this.step * 10;
-        this.beforeShowOption = `beforeShow${toTitleCase(this.cellClass)}`;
-        this.grid = this.element;
-        this.element.classList.add(this.name, 'datepicker-grid');
-        this.grid.appendChild(parseHTML(createTagRepeat('span', 12)));
-      }
-      super.init(options);
-    }
-
-    setOptions(options) {
-      if (hasProperty(options, 'minDate')) {
-        if (options.minDate === undefined) {
-          this.minYear = this.minDate = undefined;
-        } else {
-          this.minYear = startOfYearPeriod(options.minDate, this.step);
-          this.minDate = dateValue(this.minYear, 0, 1);
-        }
-      }
-      if (hasProperty(options, 'maxDate')) {
-        if (options.maxDate === undefined) {
-          this.maxYear = this.maxDate = undefined;
-        } else {
-          this.maxYear = startOfYearPeriod(options.maxDate, this.step);
-          this.maxDate = dateValue(this.maxYear, 11, 31);
-        }
-      }
-      if (options[this.beforeShowOption] !== undefined) {
-        const beforeShow = options[this.beforeShowOption];
-        this.beforeShow = typeof beforeShow === 'function' ? beforeShow : undefined;
-      }
-    }
-
-    // Update view's settings to reflect the viewDate set on the picker
-    updateFocus() {
-      const viewDate = new Date(this.picker.viewDate);
-      const first = startOfYearPeriod(viewDate, this.navStep);
-      const last = first + 9 * this.step;
-
-      this.first = first;
-      this.last = last;
-      this.start = first - this.step;
-      this.focused = startOfYearPeriod(viewDate, this.step);
-    }
-
-    // Update view's settings to reflect the selected dates
-    updateSelection() {
-      const {dates, rangepicker} = this.picker.datepicker;
-      this.selected = dates.reduce((years, timeValue) => {
-        return pushUnique(years, startOfYearPeriod(timeValue, this.step));
-      }, []);
-      if (rangepicker && rangepicker.dates) {
-        this.range = rangepicker.dates.map(timeValue => {
-          if (timeValue !== undefined) {
-            return startOfYearPeriod(timeValue, this.step);
-          }
-        });
-      }
-    }
-
-    // Update the entire view UI
-    render() {
-      // refresh disabled years on every render in order to clear the ones added
-      // by beforeShow hook at previous render
-      this.disabled = [];
-
-      this.picker.setViewSwitchLabel(`${this.first}-${this.last}`);
-      this.picker.setPrevBtnDisabled(this.first <= this.minYear);
-      this.picker.setNextBtnDisabled(this.last >= this.maxYear);
-
-      Array.from(this.grid.children).forEach((el, index) => {
-        const classList = el.classList;
-        const current = this.start + (index * this.step);
-        const date = dateValue(current, 0, 1);
-
-        el.className = `datepicker-cell ${this.cellClass}`;
-        if (this.isMinView) {
-          el.dataset.date = date;
-        }
-        el.textContent = el.dataset.year = current;
-
-        if (index === 0) {
-          classList.add('prev');
-        } else if (index === 11) {
-          classList.add('next');
-        }
-        if (current < this.minYear || current > this.maxYear) {
-          classList.add('disabled');
-        }
-        if (this.range) {
-          const [rangeStart, rangeEnd] = this.range;
-          if (current > rangeStart && current < rangeEnd) {
-            classList.add('range');
-          }
-          if (current === rangeStart) {
-            classList.add('range-start');
-          }
-          if (current === rangeEnd) {
-            classList.add('range-end');
-          }
-        }
-        if (this.selected.includes(current)) {
-          classList.add('selected');
-        }
-        if (current === this.focused) {
-          classList.add('focused');
-        }
-
-        if (this.beforeShow) {
-          this.performBeforeHook(el, current, date);
-        }
-      });
-    }
-
-    // Update the view UI by applying the changes of selected and focused items
-    refresh() {
-      const [rangeStart, rangeEnd] = this.range || [];
-      this.grid
-        .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
-        .forEach((el) => {
-          el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
-        });
-      Array.from(this.grid.children).forEach((el) => {
-        const current = Number(el.textContent);
-        const classList = el.classList;
-        if (current > rangeStart && current < rangeEnd) {
-          classList.add('range');
-        }
-        if (current === rangeStart) {
-          classList.add('range-start');
-        }
-        if (current === rangeEnd) {
-          classList.add('range-end');
-        }
-        if (this.selected.includes(current)) {
-          classList.add('selected');
-        }
-        if (current === this.focused) {
-          classList.add('focused');
-        }
-      });
-    }
-
-    // Update the view UI by applying the change of focused item
-    refreshFocus() {
-      const index = Math.round((this.focused - this.start) / this.step);
-      this.grid.querySelectorAll('.focused').forEach((el) => {
-        el.classList.remove('focused');
-      });
-      this.grid.children[index].classList.add('focused');
-    }
-  }
-
-  function triggerDatepickerEvent(datepicker, type) {
-    const detail = {
-      date: datepicker.getDate(),
-      viewDate: new Date(datepicker.picker.viewDate),
-      viewId: datepicker.picker.currentView.id,
-      datepicker,
-    };
-    datepicker.element.dispatchEvent(new CustomEvent(type, {detail}));
-  }
-
-  // direction: -1 (to previous), 1 (to next)
-  function goToPrevOrNext(datepicker, direction) {
-    const {minDate, maxDate} = datepicker.config;
-    const {currentView, viewDate} = datepicker.picker;
-    let newViewDate;
-    switch (currentView.id) {
-      case 0:
-        newViewDate = addMonths(viewDate, direction);
-        break;
-      case 1:
-        newViewDate = addYears(viewDate, direction);
-        break;
-      default:
-        newViewDate = addYears(viewDate, direction * currentView.navStep);
-    }
-    newViewDate = limitToRange(newViewDate, minDate, maxDate);
-    datepicker.picker.changeFocus(newViewDate).render();
-  }
-
-  function switchView(datepicker) {
-    const viewId = datepicker.picker.currentView.id;
-    if (viewId === datepicker.config.maxView) {
-      return;
-    }
-    datepicker.picker.changeView(viewId + 1).render();
-  }
-
-  function unfocus(datepicker) {
-    if (datepicker.config.updateOnBlur) {
-      datepicker.update({autohide: true});
-    } else {
-      datepicker.refresh('input');
-      datepicker.hide();
-    }
-  }
-
-  function goToSelectedMonthOrYear(datepicker, selection) {
-    const picker = datepicker.picker;
-    const viewDate = new Date(picker.viewDate);
-    const viewId = picker.currentView.id;
-    const newDate = viewId === 1
-      ? addMonths(viewDate, selection - viewDate.getMonth())
-      : addYears(viewDate, selection - viewDate.getFullYear());
-
-    picker.changeFocus(newDate).changeView(viewId - 1).render();
-  }
-
-  function onClickTodayBtn(datepicker) {
-    const picker = datepicker.picker;
-    const currentDate = today();
-    if (datepicker.config.todayBtnMode === 1) {
-      if (datepicker.config.autohide) {
-        datepicker.setDate(currentDate);
-        return;
-      }
-      datepicker.setDate(currentDate, {render: false});
-      picker.update();
-    }
-    if (picker.viewDate !== currentDate) {
-      picker.changeFocus(currentDate);
-    }
-    picker.changeView(0).render();
-  }
-
-  function onClickClearBtn(datepicker) {
-    datepicker.setDate({clear: true});
-  }
-
-  function onClickViewSwitch(datepicker) {
-    switchView(datepicker);
-  }
-
-  function onClickPrevBtn(datepicker) {
-    goToPrevOrNext(datepicker, -1);
-  }
-
-  function onClickNextBtn(datepicker) {
-    goToPrevOrNext(datepicker, 1);
-  }
-
-  // For the picker's main block to delegete the events from `datepicker-cell`s
-  function onClickView(datepicker, ev) {
-    const target = findElementInEventPath(ev, '.datepicker-cell');
-    if (!target || target.classList.contains('disabled')) {
-      return;
-    }
-
-    const {id, isMinView} = datepicker.picker.currentView;
-    if (isMinView) {
-      datepicker.setDate(Number(target.dataset.date));
-    } else if (id === 1) {
-      goToSelectedMonthOrYear(datepicker, Number(target.dataset.month));
-    } else {
-      goToSelectedMonthOrYear(datepicker, Number(target.dataset.year));
-    }
-  }
-
-  function onClickPicker(datepicker) {
-    if (!datepicker.inline && !datepicker.config.disableTouchKeyboard) {
-      datepicker.inputField.focus();
-    }
-  }
-
-  function processPickerOptions(picker, options) {
-    if (options.title !== undefined) {
-      if (options.title) {
-        picker.controls.title.textContent = options.title;
-        showElement(picker.controls.title);
-      } else {
-        picker.controls.title.textContent = '';
-        hideElement(picker.controls.title);
-      }
-    }
-    if (options.prevArrow) {
-      const prevBtn = picker.controls.prevBtn;
-      emptyChildNodes(prevBtn);
-      options.prevArrow.forEach((node) => {
-        prevBtn.appendChild(node.cloneNode(true));
-      });
-    }
-    if (options.nextArrow) {
-      const nextBtn = picker.controls.nextBtn;
-      emptyChildNodes(nextBtn);
-      options.nextArrow.forEach((node) => {
-        nextBtn.appendChild(node.cloneNode(true));
-      });
-    }
-    if (options.locale) {
-      picker.controls.todayBtn.textContent = options.locale.today;
-      picker.controls.clearBtn.textContent = options.locale.clear;
-    }
-    if (options.todayBtn !== undefined) {
-      if (options.todayBtn) {
-        showElement(picker.controls.todayBtn);
-      } else {
-        hideElement(picker.controls.todayBtn);
-      }
-    }
-    if (hasProperty(options, 'minDate') || hasProperty(options, 'maxDate')) {
-      const {minDate, maxDate} = picker.datepicker.config;
-      picker.controls.todayBtn.disabled = !isInRange(today(), minDate, maxDate);
-    }
-    if (options.clearBtn !== undefined) {
-      if (options.clearBtn) {
-        showElement(picker.controls.clearBtn);
-      } else {
-        hideElement(picker.controls.clearBtn);
-      }
-    }
-  }
-
-  // Compute view date to reset, which will be...
-  // - the last item of the selected dates or defaultViewDate if no selection
-  // - limitted to minDate or maxDate if it exceeds the range
-  function computeResetViewDate(datepicker) {
-    const {dates, config} = datepicker;
-    const viewDate = dates.length > 0 ? lastItemOf(dates) : config.defaultViewDate;
-    return limitToRange(viewDate, config.minDate, config.maxDate);
-  }
-
-  // Change current view's view date
-  function setViewDate(picker, newDate) {
-    const oldViewDate = new Date(picker.viewDate);
-    const newViewDate = new Date(newDate);
-    const {id, year, first, last} = picker.currentView;
-    const viewYear = newViewDate.getFullYear();
-
-    picker.viewDate = newDate;
-    if (viewYear !== oldViewDate.getFullYear()) {
-      triggerDatepickerEvent(picker.datepicker, 'changeYear');
-    }
-    if (newViewDate.getMonth() !== oldViewDate.getMonth()) {
-      triggerDatepickerEvent(picker.datepicker, 'changeMonth');
-    }
-
-    // return whether the new date is in different period on time from the one
-    // displayed in the current view
-    // when true, the view needs to be re-rendered on the next UI refresh.
-    switch (id) {
-      case 0:
-        return newDate < first || newDate > last;
-      case 1:
-        return viewYear !== year;
-      default:
-        return viewYear < first || viewYear > last;
-    }
-  }
-
-  function getTextDirection(el) {
-    return window.getComputedStyle(el).direction;
-  }
-
-  // Class representing the picker UI
-  class Picker {
-    constructor(datepicker) {
-      this.datepicker = datepicker;
-
-      const template = pickerTemplate.replace(/%buttonClass%/g, datepicker.config.buttonClass);
-      const element = this.element = parseHTML(template).firstChild;
-      const [header, main, footer] = element.firstChild.children;
-      const title = header.firstElementChild;
-      const [prevBtn, viewSwitch, nextBtn] = header.lastElementChild.children;
-      const [todayBtn, clearBtn] = footer.firstChild.children;
-      const controls = {
-        title,
-        prevBtn,
-        viewSwitch,
-        nextBtn,
-        todayBtn,
-        clearBtn,
-      };
-      this.main = main;
-      this.controls = controls;
-
-      const elementClass = datepicker.inline ? 'inline' : 'dropdown';
-      element.classList.add(`datepicker-${elementClass}`);
-
-      processPickerOptions(this, datepicker.config);
-      this.viewDate = computeResetViewDate(datepicker);
-
-      // set up event listeners
-      registerListeners(datepicker, [
-        [element, 'click', onClickPicker.bind(null, datepicker), {capture: true}],
-        [main, 'click', onClickView.bind(null, datepicker)],
-        [controls.viewSwitch, 'click', onClickViewSwitch.bind(null, datepicker)],
-        [controls.prevBtn, 'click', onClickPrevBtn.bind(null, datepicker)],
-        [controls.nextBtn, 'click', onClickNextBtn.bind(null, datepicker)],
-        [controls.todayBtn, 'click', onClickTodayBtn.bind(null, datepicker)],
-        [controls.clearBtn, 'click', onClickClearBtn.bind(null, datepicker)],
-      ]);
-
-      // set up views
-      this.views = [
-        new DaysView(this),
-        new MonthsView(this),
-        new YearsView(this, {id: 2, name: 'years', cellClass: 'year', step: 1}),
-        new YearsView(this, {id: 3, name: 'decades', cellClass: 'decade', step: 10}),
-      ];
-      this.currentView = this.views[datepicker.config.startView];
-
-      this.currentView.render();
-      this.main.appendChild(this.currentView.element);
-      datepicker.config.container.appendChild(this.element);
-    }
-
-    setOptions(options) {
-      processPickerOptions(this, options);
-      this.views.forEach((view) => {
-        view.init(options, false);
-      });
-      this.currentView.render();
-    }
-
-    detach() {
-      this.datepicker.config.container.removeChild(this.element);
-    }
-
-    show() {
-      if (this.active) {
-        return;
-      }
-      this.element.classList.add('active');
-      this.active = true;
-
-      const datepicker = this.datepicker;
-      if (!datepicker.inline) {
-        // ensure picker's direction matches input's
-        const inputDirection = getTextDirection(datepicker.inputField);
-        if (inputDirection !== getTextDirection(datepicker.config.container)) {
-          this.element.dir = inputDirection;
-        } else if (this.element.dir) {
-          this.element.removeAttribute('dir');
-        }
-
-        this.place();
-        if (datepicker.config.disableTouchKeyboard) {
-          datepicker.inputField.blur();
-        }
-      }
-      triggerDatepickerEvent(datepicker, 'show');
-    }
-
-    hide() {
-      if (!this.active) {
-        return;
-      }
-      this.datepicker.exitEditMode();
-      this.element.classList.remove('active');
-      this.active = false;
-      triggerDatepickerEvent(this.datepicker, 'hide');
-    }
-
-    place() {
-      const {classList, style} = this.element;
-      const {config, inputField} = this.datepicker;
-      const container = config.container;
-      const {
-        width: calendarWidth,
-        height: calendarHeight,
-      } = this.element.getBoundingClientRect();
-      const {
-        left: containerLeft,
-        top: containerTop,
-        width: containerWidth,
-      } = container.getBoundingClientRect();
-      const {
-        left: inputLeft,
-        top: inputTop,
-        width: inputWidth,
-        height: inputHeight
-      } = inputField.getBoundingClientRect();
-      let {x: orientX, y: orientY} = config.orientation;
-      let scrollTop;
-      let left;
-      let top;
-
-      if (container === document.body) {
-        scrollTop = window.scrollY;
-        left = inputLeft + window.scrollX;
-        top = inputTop + scrollTop;
-      } else {
-        scrollTop = container.scrollTop;
-        left = inputLeft - containerLeft;
-        top = inputTop - containerTop + scrollTop;
-      }
-
-      if (orientX === 'auto') {
-        if (left < 0) {
-          // align to the left and move into visible area if input's left edge < window's
-          orientX = 'left';
-          left = 10;
-        } else if (left + calendarWidth > containerWidth) {
-          // align to the right if canlendar's right edge > container's
-          orientX = 'right';
-        } else {
-          orientX = getTextDirection(inputField) === 'rtl' ? 'right' : 'left';
-        }
-      }
-      if (orientX === 'right') {
-        left -= calendarWidth - inputWidth;
-      }
-
-      if (orientY === 'auto') {
-        orientY = top - calendarHeight < scrollTop ? 'bottom' : 'top';
-      }
-      if (orientY === 'top') {
-        top -= calendarHeight;
-      } else {
-        top += inputHeight;
-      }
-
-      classList.remove(
-        'datepicker-orient-top',
-        'datepicker-orient-bottom',
-        'datepicker-orient-right',
-        'datepicker-orient-left'
-      );
-      classList.add(`datepicker-orient-${orientY}`, `datepicker-orient-${orientX}`);
-
-      style.top = top ? `${top}px` : top;
-      style.left = left ? `${left}px` : left;
-    }
-
-    setViewSwitchLabel(labelText) {
-      this.controls.viewSwitch.textContent = labelText;
-    }
-
-    setPrevBtnDisabled(disabled) {
-      this.controls.prevBtn.disabled = disabled;
-    }
-
-    setNextBtnDisabled(disabled) {
-      this.controls.nextBtn.disabled = disabled;
-    }
-
-    changeView(viewId) {
-      const oldView = this.currentView;
-      const newView =  this.views[viewId];
-      if (newView.id !== oldView.id) {
-        this.currentView = newView;
-        this._renderMethod = 'render';
-        triggerDatepickerEvent(this.datepicker, 'changeView');
-        this.main.replaceChild(newView.element, oldView.element);
-      }
-      return this;
-    }
-
-    // Change the focused date (view date)
-    changeFocus(newViewDate) {
-      this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refreshFocus';
-      this.views.forEach((view) => {
-        view.updateFocus();
-      });
-      return this;
-    }
-
-    // Apply the change of the selected dates
-    update() {
-      const newViewDate = computeResetViewDate(this.datepicker);
-      this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refresh';
-      this.views.forEach((view) => {
-        view.updateFocus();
-        view.updateSelection();
-      });
-      return this;
-    }
-
-    // Refresh the picker UI
-    render(quickRender = true) {
-      const renderMethod = (quickRender && this._renderMethod) || 'render';
-      delete this._renderMethod;
-
-      this.currentView[renderMethod]();
-    }
-  }
-
-  // Find the closest date that doesn't meet the condition for unavailable date
-  // Returns undefined if no available date is found
-  // addFn: function to calculate the next date
-  //   - args: time value, amount
-  // increase: amount to pass to addFn
-  // testFn: function to test the unavailablity of the date
-  //   - args: time value; retun: true if unavailable
-  function findNextAvailableOne(date, addFn, increase, testFn, min, max) {
-    if (!isInRange(date, min, max)) {
-      return;
-    }
-    if (testFn(date)) {
-      const newDate = addFn(date, increase);
-      return findNextAvailableOne(newDate, addFn, increase, testFn, min, max);
-    }
-    return date;
-  }
-
-  // direction: -1 (left/up), 1 (right/down)
-  // vertical: true for up/down, false for left/right
-  function moveByArrowKey(datepicker, ev, direction, vertical) {
-    const picker = datepicker.picker;
-    const currentView = picker.currentView;
-    const step = currentView.step || 1;
-    let viewDate = picker.viewDate;
-    let addFn;
-    let testFn;
-    switch (currentView.id) {
-      case 0:
-        if (vertical) {
-          viewDate = addDays(viewDate, direction * 7);
-        } else if (ev.ctrlKey || ev.metaKey) {
-          viewDate = addYears(viewDate, direction);
-        } else {
-          viewDate = addDays(viewDate, direction);
-        }
-        addFn = addDays;
-        testFn = (date) => currentView.disabled.includes(date);
-        break;
-      case 1:
-        viewDate = addMonths(viewDate, vertical ? direction * 4 : direction);
-        addFn = addMonths;
-        testFn = (date) => {
-          const dt = new Date(date);
-          const {year, disabled} = currentView;
-          return dt.getFullYear() === year && disabled.includes(dt.getMonth());
-        };
-        break;
-      default:
-        viewDate = addYears(viewDate, direction * (vertical ? 4 : 1) * step);
-        addFn = addYears;
-        testFn = date => currentView.disabled.includes(startOfYearPeriod(date, step));
-    }
-    viewDate = findNextAvailableOne(
-      viewDate,
-      addFn,
-      direction < 0 ? -step : step,
-      testFn,
-      currentView.minDate,
-      currentView.maxDate
-    );
-    if (viewDate !== undefined) {
-      picker.changeFocus(viewDate).render();
-    }
-  }
-
-  function onKeydown(datepicker, ev) {
-    if (ev.key === 'Tab') {
-      unfocus(datepicker);
-      return;
-    }
-
-    const picker = datepicker.picker;
-    const {id, isMinView} = picker.currentView;
-    if (!picker.active) {
-      switch (ev.key) {
-        case 'ArrowDown':
-        case 'Escape':
-          picker.show();
-          break;
-        case 'Enter':
-          datepicker.update();
-          break;
-        default:
-          return;
-      }
-    } else if (datepicker.editMode) {
-      switch (ev.key) {
-        case 'Escape':
-          picker.hide();
-          break;
-        case 'Enter':
-          datepicker.exitEditMode({update: true, autohide: datepicker.config.autohide});
-          break;
-        default:
-          return;
-      }
-    } else {
-      switch (ev.key) {
-        case 'Escape':
-          picker.hide();
-          break;
-        case 'ArrowLeft':
-          if (ev.ctrlKey || ev.metaKey) {
-            goToPrevOrNext(datepicker, -1);
-          } else if (ev.shiftKey) {
-            datepicker.enterEditMode();
-            return;
-          } else {
-            moveByArrowKey(datepicker, ev, -1, false);
-          }
-          break;
-        case 'ArrowRight':
-          if (ev.ctrlKey || ev.metaKey) {
-            goToPrevOrNext(datepicker, 1);
-          } else if (ev.shiftKey) {
-            datepicker.enterEditMode();
-            return;
-          } else {
-            moveByArrowKey(datepicker, ev, 1, false);
-          }
-          break;
-        case 'ArrowUp':
-          if (ev.ctrlKey || ev.metaKey) {
-            switchView(datepicker);
-          } else if (ev.shiftKey) {
-            datepicker.enterEditMode();
-            return;
-          } else {
-            moveByArrowKey(datepicker, ev, -1, true);
-          }
-          break;
-        case 'ArrowDown':
-          if (ev.shiftKey && !ev.ctrlKey && !ev.metaKey) {
-            datepicker.enterEditMode();
-            return;
-          }
-          moveByArrowKey(datepicker, ev, 1, true);
-          break;
-        case 'Enter':
-          if (isMinView) {
-            datepicker.setDate(picker.viewDate);
-          } else {
-            picker.changeView(id - 1).render();
-          }
-          break;
-        case 'Backspace':
-        case 'Delete':
-          datepicker.enterEditMode();
-          return;
-        default:
-          if (ev.key.length === 1 && !ev.ctrlKey && !ev.metaKey) {
-            datepicker.enterEditMode();
-          }
-          return;
-      }
-    }
-    ev.preventDefault();
-    ev.stopPropagation();
-  }
-
-  function onFocus(datepicker) {
-    if (datepicker.config.showOnFocus && !datepicker._showing) {
-      datepicker.show();
-    }
-  }
-
-  // for the prevention for entering edit mode while getting focus on click
-  function onMousedown(datepicker, ev) {
-    const el = ev.target;
-    if (datepicker.picker.active || datepicker.config.showOnClick) {
-      el._active = el === document.activeElement;
-      el._clicking = setTimeout(() => {
-        delete el._active;
-        delete el._clicking;
-      }, 2000);
-    }
-  }
-
-  function onClickInput(datepicker, ev) {
-    const el = ev.target;
-    if (!el._clicking) {
-      return;
-    }
-    clearTimeout(el._clicking);
-    delete el._clicking;
-
-    if (el._active) {
-      datepicker.enterEditMode();
-    }
-    delete el._active;
-
-    if (datepicker.config.showOnClick) {
-      datepicker.show();
-    }
-  }
-
-  function onPaste(datepicker, ev) {
-    if (ev.clipboardData.types.includes('text/plain')) {
-      datepicker.enterEditMode();
-    }
-  }
-
-  // for the `document` to delegate the events from outside the picker/input field
-  function onClickOutside(datepicker, ev) {
-    const element = datepicker.element;
-    if (element !== document.activeElement) {
-      return;
-    }
-    const pickerElem = datepicker.picker.element;
-    if (findElementInEventPath(ev, el => el === element || el === pickerElem)) {
-      return;
-    }
-    unfocus(datepicker);
-  }
-
-  function stringifyDates(dates, config) {
-    return dates
-      .map(dt => formatDate(dt, config.format, config.locale))
-      .join(config.dateDelimiter);
-  }
-
-  // parse input dates and create an array of time values for selection
-  // returns undefined if there are no valid dates in inputDates
-  // when origDates (current selection) is passed, the function works to mix
-  // the input dates into the current selection
-  function processInputDates(datepicker, inputDates, clear = false) {
-    const {config, dates: origDates, rangepicker} = datepicker;
-    if (inputDates.length === 0) {
-      // empty input is considered valid unless origiDates is passed
-      return clear ? [] : undefined;
-    }
-
-    const rangeEnd = rangepicker && datepicker === rangepicker.datepickers[1];
-    let newDates = inputDates.reduce((dates, dt) => {
-      let date = parseDate(dt, config.format, config.locale);
-      if (date === undefined) {
-        return dates;
-      }
-      if (config.pickLevel > 0) {
-        // adjust to 1st of the month/Jan 1st of the year
-        // or to the last day of the monh/Dec 31st of the year if the datepicker
-        // is the range-end picker of a rangepicker
-        const dt = new Date(date);
-        if (config.pickLevel === 1) {
-          date = rangeEnd
-            ? dt.setMonth(dt.getMonth() + 1, 0)
-            : dt.setDate(1);
-        } else {
-          date = rangeEnd
-            ? dt.setFullYear(dt.getFullYear() + 1, 0, 0)
-            : dt.setMonth(0, 1);
-        }
-      }
-      if (
-        isInRange(date, config.minDate, config.maxDate)
-        && !dates.includes(date)
-        && !config.datesDisabled.includes(date)
-        && !config.daysOfWeekDisabled.includes(new Date(date).getDay())
-      ) {
-        dates.push(date);
-      }
-      return dates;
-    }, []);
-    if (newDates.length === 0) {
-      return;
-    }
-    if (config.multidate && !clear) {
-      // get the synmetric difference between origDates and newDates
-      newDates = newDates.reduce((dates, date) => {
-        if (!origDates.includes(date)) {
-          dates.push(date);
-        }
-        return dates;
-      }, origDates.filter(date => !newDates.includes(date)));
-    }
-    // do length check always because user can input multiple dates regardless of the mode
-    return config.maxNumberOfDates && newDates.length > config.maxNumberOfDates
-      ? newDates.slice(config.maxNumberOfDates * -1)
-      : newDates;
-  }
-
-  // refresh the UI elements
-  // modes: 1: input only, 2, picker only, 3 both
-  function refreshUI(datepicker, mode = 3, quickRender = true) {
-    const {config, picker, inputField} = datepicker;
-    if (mode & 2) {
-      const newView = picker.active ? config.pickLevel : config.startView;
-      picker.update().changeView(newView).render(quickRender);
-    }
-    if (mode & 1 && inputField) {
-      inputField.value = stringifyDates(datepicker.dates, config);
-    }
-  }
-
-  function setDate(datepicker, inputDates, options) {
-    let {clear, render, autohide} = options;
-    if (render === undefined) {
-      render = true;
-    }
-    if (!render) {
-      autohide = false;
-    } else if (autohide === undefined) {
-      autohide = datepicker.config.autohide;
-    }
-
-    const newDates = processInputDates(datepicker, inputDates, clear);
-    if (!newDates) {
-      return;
-    }
-    if (newDates.toString() !== datepicker.dates.toString()) {
-      datepicker.dates = newDates;
-      refreshUI(datepicker, render ? 3 : 1);
-      triggerDatepickerEvent(datepicker, 'changeDate');
-    } else {
-      refreshUI(datepicker, 1);
-    }
-    if (autohide) {
-      datepicker.hide();
-    }
-  }
-
-  /**
-   * Class representing a date picker
-   */
-  class Datepicker {
-    /**
-     * Create a date picker
-     * @param  {Element} element - element to bind a date picker
-     * @param  {Object} [options] - config options
-     * @param  {DateRangePicker} [rangepicker] - DateRangePicker instance the
-     * date picker belongs to. Use this only when creating date picker as a part
-     * of date range picker
-     */
-    constructor(element, options = {}, rangepicker = undefined) {
-      element.datepicker = this;
-      this.element = element;
-
-      // set up config
-      const config = this.config = Object.assign({
-        buttonClass: (options.buttonClass && String(options.buttonClass)) || 'button',
-        container: document.body,
-        defaultViewDate: today(),
-        maxDate: undefined,
-        minDate: undefined,
-      }, processOptions(defaultOptions, this));
-      this._options = options;
-      Object.assign(config, processOptions(options, this));
-
-      // configure by type
-      const inline = this.inline = element.tagName !== 'INPUT';
-      let inputField;
-      let initialDates;
-
-      if (inline) {
-        config.container = element;
-        initialDates = stringToArray(element.dataset.date, config.dateDelimiter);
-        delete element.dataset.date;
-      } else {
-        const container = options.container ? document.querySelector(options.container) : null;
-        if (container) {
-          config.container = container;
-        }
-        inputField = this.inputField = element;
-        inputField.classList.add('datepicker-input');
-        initialDates = stringToArray(inputField.value, config.dateDelimiter);
-      }
-      if (rangepicker) {
-        // check validiry
-        const index = rangepicker.inputs.indexOf(inputField);
-        const datepickers = rangepicker.datepickers;
-        if (index < 0 || index > 1 || !Array.isArray(datepickers)) {
-          throw Error('Invalid rangepicker object.');
-        }
-        // attach itaelf to the rangepicker here so that processInputDates() can
-        // determine if this is the range-end picker of the rangepicker while
-        // setting inital values when pickLevel > 0
-        datepickers[index] = this;
-        // add getter for rangepicker
-        Object.defineProperty(this, 'rangepicker', {
-          get() {
-            return rangepicker;
-          },
-        });
-      }
-
-      // set initial dates
-      this.dates = [];
-      // process initial value
-      const inputDateValues = processInputDates(this, initialDates);
-      if (inputDateValues && inputDateValues.length > 0) {
-        this.dates = inputDateValues;
-      }
-      if (inputField) {
-        inputField.value = stringifyDates(this.dates, config);
-      }
-
-      const picker = this.picker = new Picker(this);
-
-      if (inline) {
-        this.show();
-      } else {
-        // set up event listeners in other modes
-        const onMousedownDocument = onClickOutside.bind(null, this);
-        const listeners = [
-          [inputField, 'keydown', onKeydown.bind(null, this)],
-          [inputField, 'focus', onFocus.bind(null, this)],
-          [inputField, 'mousedown', onMousedown.bind(null, this)],
-          [inputField, 'click', onClickInput.bind(null, this)],
-          [inputField, 'paste', onPaste.bind(null, this)],
-          [document, 'mousedown', onMousedownDocument],
-          [document, 'touchstart', onMousedownDocument],
-          [window, 'resize', picker.place.bind(picker)]
-        ];
-        registerListeners(this, listeners);
-      }
-    }
-
-    /**
-     * Format Date object or time value in given format and language
-     * @param  {Date|Number} date - date or time value to format
-     * @param  {String|Object} format - format string or object that contains
-     * toDisplay() custom formatter, whose signature is
-     * - args:
-     *   - date: {Date} - Date instance of the date passed to the method
-     *   - format: {Object} - the format object passed to the method
-     *   - locale: {Object} - locale for the language specified by `lang`
-     * - return:
-     *     {String} formatted date
-     * @param  {String} [lang=en] - language code for the locale to use
-     * @return {String} formatted date
-     */
-    static formatDate(date, format, lang) {
-      return formatDate(date, format, lang && locales[lang] || locales.en);
-    }
-
-    /**
-     * Parse date string
-     * @param  {String|Date|Number} dateStr - date string, Date object or time
-     * value to parse
-     * @param  {String|Object} format - format string or object that contains
-     * toValue() custom parser, whose signature is
-     * - args:
-     *   - dateStr: {String|Date|Number} - the dateStr passed to the method
-     *   - format: {Object} - the format object passed to the method
-     *   - locale: {Object} - locale for the language specified by `lang`
-     * - return:
-     *     {Date|Number} parsed date or its time value
-     * @param  {String} [lang=en] - language code for the locale to use
-     * @return {Number} time value of parsed date
-     */
-    static parseDate(dateStr, format, lang) {
-      return parseDate(dateStr, format, lang && locales[lang] || locales.en);
-    }
-
-    /**
-     * @type {Object} - Installed locales in `[languageCode]: localeObject` format
-     * en`:_English (US)_ is pre-installed.
-     */
-    static get locales() {
-      return locales;
-    }
-
-    /**
-     * @type {Boolean} - Whether the picker element is shown. `true` whne shown
-     */
-    get active() {
-      return !!(this.picker && this.picker.active);
-    }
-
-    /**
-     * @type {HTMLDivElement} - DOM object of picker element
-     */
-    get pickerElement() {
-      return this.picker ? this.picker.element : undefined;
-    }
-
-    /**
-     * Set new values to the config options
-     * @param {Object} options - config options to update
-     */
-    setOptions(options) {
-      const picker = this.picker;
-      const newOptions = processOptions(options, this);
-      Object.assign(this._options, options);
-      Object.assign(this.config, newOptions);
-      picker.setOptions(newOptions);
-
-      refreshUI(this, 3);
-    }
-
-    /**
-     * Show the picker element
-     */
-    show() {
-      if (this.inputField) {
-        if (this.inputField.disabled) {
-          return;
-        }
-        if (this.inputField !== document.activeElement) {
-          this._showing = true;
-          this.inputField.focus();
-          delete this._showing;
-        }
-      }
-      this.picker.show();
-    }
-
-    /**
-     * Hide the picker element
-     * Not available on inline picker
-     */
-    hide() {
-      if (this.inline) {
-        return;
-      }
-      this.picker.hide();
-      this.picker.update().changeView(this.config.startView).render();
-    }
-
-    /**
-     * Destroy the Datepicker instance
-     * @return {Detepicker} - the instance destroyed
-     */
-    destroy() {
-      this.hide();
-      unregisterListeners(this);
-      this.picker.detach();
-      if (!this.inline) {
-        this.inputField.classList.remove('datepicker-input');
-      }
-      delete this.element.datepicker;
-      return this;
-    }
-
-    /**
-     * Get the selected date(s)
-     *
-     * The method returns a Date object of selected date by default, and returns
-     * an array of selected dates in multidate mode. If format string is passed,
-     * it returns date string(s) formatted in given format.
-     *
-     * @param  {String} [format] - Format string to stringify the date(s)
-     * @return {Date|String|Date[]|String[]} - selected date(s), or if none is
-     * selected, empty array in multidate mode and untitled in sigledate mode
-     */
-    getDate(format = undefined) {
-      const callback = format
-        ? date => formatDate(date, format, this.config.locale)
-        : date => new Date(date);
-
-      if (this.config.multidate) {
-        return this.dates.map(callback);
-      }
-      if (this.dates.length > 0) {
-        return callback(this.dates[0]);
-      }
-    }
-
-    /**
-     * Set selected date(s)
-     *
-     * In multidate mode, you can pass multiple dates as a series of arguments
-     * or an array. (Since each date is parsed individually, the type of the
-     * dates doesn't have to be the same.)
-     * The given dates are used to toggle the select status of each date. The
-     * number of selected dates is kept from exceeding the length set to
-     * maxNumberOfDates.
-     *
-     * With clear: true option, the method can be used to clear the selection
-     * and to replace the selection instead of toggling in multidate mode.
-     * If the option is passed with no date arguments or an empty dates array,
-     * it works as "clear" (clear the selection then set nothing), and if the
-     * option is passed with new dates to select, it works as "replace" (clear
-     * the selection then set the given dates)
-     *
-     * When render: false option is used, the method omits re-rendering the
-     * picker element. In this case, you need to call refresh() method later in
-     * order for the picker element to reflect the changes. The input field is
-     * refreshed always regardless of this option.
-     *
-     * When invalid (unparsable, repeated, disabled or out-of-range) dates are
-     * passed, the method ignores them and applies only valid ones. In the case
-     * that all the given dates are invalid, which is distinguished from passing
-     * no dates, the method considers it as an error and leaves the selection
-     * untouched.
-     *
-     * @param {...(Date|Number|String)|Array} [dates] - Date strings, Date
-     * objects, time values or mix of those for new selection
-     * @param {Object} [options] - function options
-     * - clear: {boolean} - Whether to clear the existing selection
-     *     defualt: false
-     * - render: {boolean} - Whether to re-render the picker element
-     *     default: true
-     * - autohide: {boolean} - Whether to hide the picker element after re-render
-     *     Ignored when used with render: false
-     *     default: config.autohide
-     */
-    setDate(...args) {
-      const dates = [...args];
-      const opts = {};
-      const lastArg = lastItemOf(args);
-      if (
-        typeof lastArg === 'object'
-        && !Array.isArray(lastArg)
-        && !(lastArg instanceof Date)
-        && lastArg
-      ) {
-        Object.assign(opts, dates.pop());
-      }
-
-      const inputDates = Array.isArray(dates[0]) ? dates[0] : dates;
-      setDate(this, inputDates, opts);
-    }
-
-    /**
-     * Update the selected date(s) with input field's value
-     * Not available on inline picker
-     *
-     * The input field will be refreshed with properly formatted date string.
-     *
-     * @param  {Object} [options] - function options
-     * - autohide: {boolean} - whether to hide the picker element after refresh
-     *     default: false
-     */
-    update(options = undefined) {
-      if (this.inline) {
-        return;
-      }
-
-      const opts = {clear: true, autohide: !!(options && options.autohide)};
-      const inputDates = stringToArray(this.inputField.value, this.config.dateDelimiter);
-      setDate(this, inputDates, opts);
-    }
-
-    /**
-     * Refresh the picker element and the associated input field
-     * @param {String} [target] - target item when refreshing one item only
-     * 'picker' or 'input'
-     * @param {Boolean} [forceRender] - whether to re-render the picker element
-     * regardless of its state instead of optimized refresh
-     */
-    refresh(target = undefined, forceRender = false) {
-      if (target && typeof target !== 'string') {
-        forceRender = target;
-        target = undefined;
-      }
-
-      let mode;
-      if (target === 'picker') {
-        mode = 2;
-      } else if (target === 'input') {
-        mode = 1;
-      } else {
-        mode = 3;
-      }
-      refreshUI(this, mode, !forceRender);
-    }
-
-    /**
-     * Enter edit mode
-     * Not available on inline picker or when the picker element is hidden
-     */
-    enterEditMode() {
-      if (this.inline || !this.picker.active || this.editMode) {
-        return;
-      }
-      this.editMode = true;
-      this.inputField.classList.add('in-edit');
-    }
-
-    /**
-     * Exit from edit mode
-     * Not available on inline picker
-     * @param  {Object} [options] - function options
-     * - update: {boolean} - whether to call update() after exiting
-     *     If false, input field is revert to the existing selection
-     *     default: false
-     */
-    exitEditMode(options = undefined) {
-      if (this.inline || !this.editMode) {
-        return;
-      }
-      const opts = Object.assign({update: false}, options);
-      delete this.editMode;
-      this.inputField.classList.remove('in-edit');
-      if (opts.update) {
-        this.update(opts);
-      }
-    }
-  }
-
   /*
    * Licensed to the Apache Software Foundation (ASF) under one or more
    * contributor license agreements.  See the NOTICE file distributed with
@@ -10119,78 +7576,64 @@
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
-  class DatePicker extends HTMLElement {
+  class InputSupport {
+      constructor(type) {
+          this.type = type;
+          this.support = InputSupport.checkSupport(type);
+      }
+      static checkSupport(type) {
+          const input = document.createElement("input");
+          input.setAttribute("type", type);
+          const INVALID_TEXT = "this is not a date";
+          input.setAttribute("value", INVALID_TEXT);
+          return input.value !== INVALID_TEXT;
+      }
+      example(step) {
+          switch (this.type) {
+              case "date":
+                  return InputSupport.YEAR_MONTH + "-20";
+              case "time":
+                  switch (step) {
+                      case 1:
+                          return "20:15:00";
+                      case 0.001:
+                          return "20:15:00.000";
+                      default:
+                          return "20:15";
+                  }
+              case "datetime-local":
+                  switch (step) {
+                      case 1:
+                          return InputSupport.YEAR_MONTH + "-20T20:15:00";
+                      case 0.001:
+                          return InputSupport.YEAR_MONTH + "-20T20:15:00.000";
+                      default:
+                          return InputSupport.YEAR_MONTH + "-20T20:15";
+                  }
+              case "month":
+                  return InputSupport.YEAR_MONTH;
+              case "week":
+                  return InputSupport.YEAR_MONTH.substr(0, 4) + "-W52";
+              default:
+                  return "";
+          }
+      }
+  }
+  InputSupport.YEAR_MONTH = `${new Date().toISOString().substr(0, 7)}`;
+  class TobagoDate extends HTMLElement {
       constructor() {
           super();
       }
       connectedCallback() {
-          if (this.type == "date") {
-              console.debug("check input type=date support", DatePicker.SUPPORTS_INPUT_TYPE_DATE);
-              if (!DatePicker.SUPPORTS_INPUT_TYPE_DATE) {
-                  this.setAttribute("type", "text");
-                  this.initVanillaDatePicker();
-              }
+          const support = TobagoDate.SUPPORTS[this.type];
+          console.debug("check input type support", this.type, support);
+          if (!(support === null || support === void 0 ? void 0 : support.support)) {
+              this.type = "text";
+              this.field.placeholder = support.example(this.step) + " " + (this.pattern ? this.pattern : "");
           }
       }
-      initVanillaDatePicker() {
-          var _a;
-          const field = this.field;
-          const locale = Page.page(this).locale;
-          const i18n = this.i18n;
-          i18n.titleFormat = "MM y"; // todo i18n
-          i18n.format = this.pattern;
-          Datepicker.locales[locale] = i18n;
-          const options = {
-              buttonClass: "btn",
-              orientation: "auto",
-              autohide: true,
-              language: locale,
-              todayBtn: this.todayButton,
-              todayBtnMode: 1,
-              minDate: this.min,
-              maxDate: this.max,
-              // todo readonly
-              // todo show week numbers
-          };
-          const datepicker = new Datepicker(field, options);
-          // XXX these listeners are needed as long as we have a solution for:
-          // XXX https://github.com/mymth/vanillajs-datepicker/issues/13
-          // XXX the 2nd point is missing the "normal" change event on the input element
-          field.addEventListener("keyup", (event) => {
-              // console.info("event -----> ", event.type);
-              if (event.metaKey || event.key.length > 1 && event.key !== "Backspace" && event.key !== "Delete") {
-                  return;
-              }
-              // back up user's input when user types printable character or backspace/delete
-              const target = event.target;
-              target._oldValue = target.value;
-          });
-          field.addEventListener("focus", (event) => {
-              // console.info("event -----> ", event.type);
-              this.lastValue = field.value;
-          });
-          field.addEventListener("blur", (event) => {
-              // console.info("event -----> ", event.type);
-              const target = event.target;
-              // no-op when user goes to another window or the input field has no backed-up value
-              if (document.hasFocus() && target._oldValue !== undefined) {
-                  if (target._oldValue !== target.value) {
-                      target.datepicker.setDate(target._oldValue || { clear: true });
-                  }
-                  delete target._oldValue;
-              }
-              if (this.lastValue !== field.value) {
-                  field.dispatchEvent(new Event("change"));
-              }
-          });
-          datepicker.element.addEventListener("changeDate", (event) => {
-              // console.info("event -----> ", event.type);
-              field.dispatchEvent(new Event("change"));
-          });
-          // simple solution for the picker: currently only open, not close is implemented
-          (_a = this.querySelector(".tobago-date-picker")) === null || _a === void 0 ? void 0 : _a.addEventListener("click", (event) => {
-              this.field.focus();
-          });
+      workaround() {
+          window.alert("workaround!");
       }
       get todayButton() {
           return this.hasAttribute("today-button");
@@ -10207,6 +7650,10 @@
           var _a;
           return (_a = this.field) === null || _a === void 0 ? void 0 : _a.getAttribute("type");
       }
+      set type(type) {
+          var _a;
+          (_a = this.field) === null || _a === void 0 ? void 0 : _a.setAttribute("type", type);
+      }
       get min() {
           var _a;
           return (_a = this.field) === null || _a === void 0 ? void 0 : _a.getAttribute("min");
@@ -10215,29 +7662,28 @@
           var _a;
           return (_a = this.field) === null || _a === void 0 ? void 0 : _a.getAttribute("max");
       }
-      get pattern() {
-          let pattern = this.getAttribute("pattern");
-          return pattern ? pattern : "yyyy-mm-dd";
+      get step() {
+          var _a;
+          return Number.parseFloat((_a = this.field) === null || _a === void 0 ? void 0 : _a.getAttribute("step"));
       }
-      get i18n() {
-          const i18n = this.getAttribute("i18n");
-          return i18n ? JSON.parse(i18n) : undefined;
+      get pattern() {
+          return this.getAttribute("pattern");
       }
       get field() {
           const rootNode = this.getRootNode();
           return rootNode.getElementById(this.id + "::field");
       }
   }
-  DatePicker.SUPPORTS_INPUT_TYPE_DATE = (() => {
-      const input = document.createElement("input");
-      input.setAttribute("type", "date");
-      const thisIsNoDate = "this is not a date";
-      input.setAttribute("value", thisIsNoDate);
-      return input.value !== thisIsNoDate;
-  })();
+  TobagoDate.SUPPORTS = {
+      "date": new InputSupport("date"),
+      "time": new InputSupport("time"),
+      "datetime-local": new InputSupport("datetime-local"),
+      "month": new InputSupport("month"),
+      "week": new InputSupport("week")
+  };
   document.addEventListener("tobago.init", function (event) {
       if (window.customElements.get("tobago-date") == null) {
-          window.customElements.define("tobago-date", DatePicker);
+          window.customElements.define("tobago-date", TobagoDate);
       }
   });
 
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
index 3aaa898..887d546 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago.js","sources":["../ts/tobago-utils.ts","../ts/tobago-bar.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../../../node_modules/@popperjs/core/lib/utils/getBasePlacement [...]
\ No newline at end of file
+{"version":3,"file":"tobago.js","sources":["../ts/tobago-utils.ts","../ts/tobago-bar.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../../../node_modules/@popperjs/core/lib/utils/getBasePlacement [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js
index 0f0d527..8c93f3c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js
@@ -1,8 +1,8 @@
-!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";class e{static selfOrQuerySelectorAll(e,t){const s=new Array;e||(e=document.documentElement),e.matches(t)&&s.push(e);for(const i of e.querySelectorAll(t))s.push(i);return s}static getTransitionTime(e){const t=window.getComputedStyle(e);return 1e3*(Number.parseFloat(t.transitionDelay)+Number.parseFloat(t.transitionDuration))}}class t extends HTMLElement{constructor(){super(),this.CssClass={SHOW:"sho [...]
+!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";class e{static selfOrQuerySelectorAll(e,t){const s=new Array;e||(e=document.documentElement),e.matches(t)&&s.push(e);for(const n of e.querySelectorAll(t))s.push(n);return s}static getTransitionTime(e){const t=window.getComputedStyle(e);return 1e3*(Number.parseFloat(t.transitionDelay)+Number.parseFloat(t.transitionDuration))}}class t extends HTMLElement{constructor(){super(),this.CssClass={SHOW:"sho [...]
 /*!
     * Bootstrap v5.1.2 (https://getbootstrap.com/)
     * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
     */
-const Ne="transitionend",Me=e=>{let t=e.getAttribute("data-bs-target");if(!t||"#"===t){let s=e.getAttribute("href");if(!s||!s.includes("#")&&!s.startsWith("."))return null;s.includes("#")&&!s.startsWith("#")&&(s=`#${s.split("#")[1]}`),t=s&&"#"!==s?s.trim():null}return t},Be=e=>{const t=Me(e);return t&&document.querySelector(t)?t:null},Re=e=>{const t=Me(e);return t?document.querySelector(t):null},je=e=>{e.dispatchEvent(new Event(Ne))},He=e=>!(!e||"object"!=typeof e)&&(void 0!==e.jquery&&( [...]
+const Re="transitionend",De=e=>{let t=e.getAttribute("data-bs-target");if(!t||"#"===t){let s=e.getAttribute("href");if(!s||!s.includes("#")&&!s.startsWith("."))return null;s.includes("#")&&!s.startsWith("#")&&(s=`#${s.split("#")[1]}`),t=s&&"#"!==s?s.trim():null}return t},Me=e=>{const t=De(e);return t&&document.querySelector(t)?t:null},je=e=>{const t=De(e);return t?document.querySelector(t):null},He=e=>{e.dispatchEvent(new Event(Re))},Be=e=>!(!e||"object"!=typeof e)&&(void 0!==e.jquery&&( [...]
 //# sourceMappingURL=tobago.min.js.map
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map
index 2396a03..364107c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago.min.js","sources":["../ts/tobago-utils.ts","../ts/tobago-bar.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../../../node_modules/@popperjs/core/lib/utils/getBasePlace [...]
\ No newline at end of file
+{"version":3,"file":"tobago.min.js","sources":["../ts/tobago-utils.ts","../ts/tobago-bar.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../../../node_modules/@popperjs/core/lib/utils/getBasePlace [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/scss/tobago-theme.scss b/tobago-theme/tobago-theme-standard/src/main/scss/tobago-theme.scss
index 72ffaeb..ca06198 100644
--- a/tobago-theme/tobago-theme-standard/src/main/scss/tobago-theme.scss
+++ b/tobago-theme/tobago-theme-standard/src/main/scss/tobago-theme.scss
@@ -17,9 +17,4 @@
 
 @import "node_modules/bootstrap/scss/bootstrap";
 
-// XXX patched because of bs5 (begin)
-//@import "node_modules/vanillajs-datepicker/sass/datepicker-bs4";
-@import "../../../../src/main/scss/datepicker-bs5";
-// XXX patched because of bs5 (end)
-
 @import "../../../../src/main/scss/_tobago";
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-date.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-date.ts
index 31590c6..bf9dd14 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-date.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-date.ts
@@ -15,130 +15,83 @@
  * limitations under the License.
  */
 
-// @ts-ignore
-import {Datepicker} from "vanillajs-datepicker";
-import {Page} from "./tobago-page";
-
-interface DatePickerI18n {
-  days: string[];
-  daysShort: string[];
-  daysMin: string[];
-  months: string[];
-  monthsShort: string[];
-  today: string;
-  monthsTitle: string;
-  clear: string;
-  weekStart: number;
-  format: string;
-  titleFormat: string;
-}
+class InputSupport {
 
-interface DatePickerOptions {
-  buttonClass: string;
-  orientation: string;
-  autohide: boolean;
-  language: string;
-  todayBtn: boolean;
-  todayBtnMode: number;
-  minDate: string;
-  maxDate: string;
-}
+  static readonly YEAR_MONTH = `${new Date().toISOString().substr(0, 7)}`;
 
-class DatePicker extends HTMLElement {
+  readonly type: string;
+  readonly support: boolean;
 
-  static readonly SUPPORTS_INPUT_TYPE_DATE : boolean = (() => {
+  constructor(type: string) {
+    this.type = type;
+    this.support = InputSupport.checkSupport(type);
+  }
+
+  private static checkSupport(type: string): boolean {
     const input = document.createElement("input");
-    input.setAttribute("type","date");
-    const thisIsNoDate = "this is not a date";
-    input.setAttribute("value", thisIsNoDate);
-    return input.value !== thisIsNoDate;
-  })();
+    input.setAttribute("type", type);
+    const INVALID_TEXT = "this is not a date";
+    input.setAttribute("value", INVALID_TEXT);
+    return input.value !== INVALID_TEXT;
+  }
+
+  example(step: number): string {
+    switch (this.type) {
+      case "date":
+        return InputSupport.YEAR_MONTH + "-20";
+      case "time":
+        switch (step) {
+          case 1:
+            return "20:15:00";
+          case 0.001:
+            return "20:15:00.000";
+          default:
+            return "20:15";
+        }
+      case "datetime-local":
+        switch (step) {
+          case 1:
+            return InputSupport.YEAR_MONTH + "-20T20:15:00";
+          case 0.001:
+            return InputSupport.YEAR_MONTH + "-20T20:15:00.000";
+          default:
+            return InputSupport.YEAR_MONTH + "-20T20:15";
+        }
+      case "month":
+        return InputSupport.YEAR_MONTH;
+      case "week":
+        return InputSupport.YEAR_MONTH.substr(0, 4) + "-W52";
+      default:
+        return "";
+    }
+  }
+}
+
+class TobagoDate extends HTMLElement {
 
-  lastValue: string;
+  private static readonly SUPPORTS = {
+    "date": new InputSupport("date"),
+    "time": new InputSupport("time"),
+    "datetime-local": new InputSupport("datetime-local"),
+    "month": new InputSupport("month"),
+    "week": new InputSupport("week")
+  };
 
   constructor() {
     super();
   }
 
   connectedCallback(): void {
-    if (this.type == "date") {
-      console.debug("check input type=date support", DatePicker.SUPPORTS_INPUT_TYPE_DATE);
-      if (!DatePicker.SUPPORTS_INPUT_TYPE_DATE) {
-        this.setAttribute("type", "text");
-        this.initVanillaDatePicker();
-      }
+    const support: InputSupport = TobagoDate.SUPPORTS[this.type];
+    console.debug("check input type support", this.type, support);
+    if (!support?.support) {
+      this.type = "text";
+      this.field.placeholder = support.example(this.step) + " " + (this.pattern ? this.pattern : "");
     }
   }
 
-  initVanillaDatePicker(): void {
-    const field = this.field;
-    const locale: string = Page.page(this).locale;
-
-    const i18n = this.i18n;
-    i18n.titleFormat = "MM y"; // todo i18n
-    i18n.format = this.pattern;
-    Datepicker.locales[locale] = i18n;
-
-    const options: DatePickerOptions = {
-      buttonClass: "btn",
-      orientation: "auto",
-      autohide: true,
-      language: locale,
-      todayBtn: this.todayButton,
-      todayBtnMode: 1,
-      minDate: this.min,
-      maxDate: this.max,
-      // todo readonly
-      // todo show week numbers
-    };
-    const datepicker = new Datepicker(field, options);
-
-    // XXX these listeners are needed as long as we have a solution for:
-    // XXX https://github.com/mymth/vanillajs-datepicker/issues/13
-    // XXX the 2nd point is missing the "normal" change event on the input element
-    field.addEventListener("keyup", (event) => {
-      // console.info("event -----> ", event.type);
-      if (event.metaKey || event.key.length > 1 && event.key !== "Backspace" && event.key !== "Delete") {
-        return;
-      }
-      // back up user's input when user types printable character or backspace/delete
-      const target = event.target as any;
-      target._oldValue = target.value;
-    });
-
-    field.addEventListener("focus", (event) => {
-      // console.info("event -----> ", event.type);
-      this.lastValue = field.value;
-    });
-
-    field.addEventListener("blur", (event) => {
-      // console.info("event -----> ", event.type);
-      const target = event.target as any;
-
-      // no-op when user goes to another window or the input field has no backed-up value
-      if (document.hasFocus() && target._oldValue !== undefined) {
-        if (target._oldValue !== target.value) {
-          target.datepicker.setDate(target._oldValue || {clear: true});
-        }
-        delete target._oldValue;
-      }
-
-      if (this.lastValue !== field.value) {
-        field.dispatchEvent(new Event("change"));
-      }
-    });
-
-    datepicker.element.addEventListener("changeDate", (event) => {
-      // console.info("event -----> ", event.type);
-      field.dispatchEvent(new Event("change"));
-    });
-
-    // simple solution for the picker: currently only open, not close is implemented
-    this.querySelector(".tobago-date-picker")?.addEventListener("click",
-        (event: MouseEvent) => {
-          this.field.focus();
-        }
-    );
+  workaround(): void {
+    window.alert("workaround!");
   }
 
   get todayButton(): boolean {
@@ -157,6 +110,10 @@ class DatePicker extends HTMLElement {
     return this.field?.getAttribute("type");
   }
 
+  set type(type: string) {
+    this.field?.setAttribute("type", type);
+  }
+
   get min(): string {
     return this.field?.getAttribute("min");
   }
@@ -165,14 +122,12 @@ class DatePicker extends HTMLElement {
     return this.field?.getAttribute("max");
   }
 
-  get pattern(): string {
-    let pattern = this.getAttribute("pattern");
-    return pattern ? pattern : "yyyy-mm-dd";
+  get step(): number {
+    return Number.parseFloat(this.field?.getAttribute("step"));
   }
 
-  get i18n(): DatePickerI18n {
-    const i18n = this.getAttribute("i18n");
-    return i18n ? JSON.parse(i18n) : undefined;
+  get pattern(): string {
+    return this.getAttribute("pattern");
   }
 
   get field(): HTMLInputElement {
@@ -183,6 +138,6 @@ class DatePicker extends HTMLElement {
 
 document.addEventListener("tobago.init", function (event: Event): void {
   if (window.customElements.get("tobago-date") == null) {
-    window.customElements.define("tobago-date", DatePicker);
+    window.customElements.define("tobago-date", TobagoDate);
   }
 });
diff --git a/tobago-tool/tobago-tool-apt/src/main/resources/org/apache/myfaces/tobago/apt/component.stg b/tobago-tool/tobago-tool-apt/src/main/resources/org/apache/myfaces/tobago/apt/component.stg
index d546745..f903fb9 100644
--- a/tobago-tool/tobago-tool-apt/src/main/resources/org/apache/myfaces/tobago/apt/component.stg
+++ b/tobago-tool/tobago-tool-apt/src/main/resources/org/apache/myfaces/tobago/apt/component.stg
@@ -403,7 +403,7 @@ JustifyContentProperty(property) ::= <<
 <NormalProperty(property)>
 >>
 
-HtmlInputTypesProperty(property) ::= <<
+DateTypeProperty(property) ::= <<
 <NormalProperty(property)>
 >>