DateTimePicker disable specific dates?

I found the open issue: DatePicker support for disabling arbitrary dates · Issue #2867 · vaadin/platform · GitHub
however I need support for this right now, is there anyone that already has some code for this available?

This should set the background of all days to red, however it randomly misses a few, any ideas why:

document.querySelectorAll("vaadin-date-picker-overlay-content > vaadin-date-picker-month-scroller > div > vaadin-month-calendar").forEach(el => {el.shadowRoot.querySelectorAll("#days-container > tr > td").forEach(e=>{e.style.background="red"})})

There is no really good answer to that, but as mentioned in the ticket, you can in some cases use the aria-labels as a workaround to disable the pointer events for specific dates

And then in addition to that use validator naturally that does not allow the dates you do not want.

We recently received a contribution that makes this possible for the date picker web component. However there is no Flow API for it yet, so it can only be accessed through JS. It’s also only in 24.4, which is still in alpha at the moment.

If that’s an option for you, here’s an example for disabling the 14.04.2024:

DateTimePicker picker = new DateTimePicker();
picker.getElement().executeJs("""
        this.querySelector('vaadin-date-picker').isDateDisabled = (date) => {
            return date.year === 2024 && date.month === 3 && date.day === 14;
        }
        """);

@sissbruecker @Tatu2

Was able to somewhat implement something that should work on vaadin 14+.
However it breaks if the user scrolls a little further, any ideas how to fix that?

package com.osiris.localbusinesses.ui;

import com.vaadin.flow.component.datetimepicker.DateTimePicker;
import com.vaadin.flow.dom.DomListenerRegistration;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class DateTimePicker2 extends DateTimePicker {
    public List<LocalDateTime> enabledDates;
    public List<LocalDateTime> disabledDates;
    public DomListenerRegistration onClick;

    public DateTimePicker2() {
        this(new ArrayList<>(), new ArrayList<>());
    }

    public DateTimePicker2(List<LocalDateTime> enabledDates, List<LocalDateTime> disabledDates) {
        this.enabledDates = enabledDates;
        this.disabledDates = disabledDates;
        updateDates();

        this.onClick = getElement().addEventListener("click", e -> {
            updateDates();
        });
    }

    /**
     * Disabled dates will overwrite enabled dates (if any).
     */
    public void updateDates() {
        String jsArrayDisabled = toJSArray(this.disabledDates);
        String jsArrayEnabled = toJSArray(this.enabledDates);
        //System.out.println(jsArrayEnabled);
        //System.out.println(jsArrayDisabled);

        if (!this.enabledDates.isEmpty())
            getElement().executeJs("" +
                    "let array = " + jsArrayEnabled + ";\n" +
                    "document.querySelectorAll(\"vaadin-date-picker-overlay-content > vaadin-date-picker-month-scroller > div > vaadin-month-calendar\").forEach(el => {el.shadowRoot.querySelectorAll(\"#days-container > tr > td\")" +
                    ".forEach(e=>{" +
                    //"   console.log('Checking if enabled date:', e.ariaLabel);" + // Debugging statement
                    "   if (!array.includes(e.ariaLabel)) {" +
                    //"       console.log('Disabling date:', e.ariaLabel);" + // Debugging statement
                    "       e.setAttribute(\"aria-disabled\", true);e.setAttribute(\"disabled\", true);e.setAttribute(\"part\", \"date disabled\");e.style.pointerEvents = \"none\";" +
                    "   } else e.setAttribute(\"aria-disabled\", false);e.setAttribute(\"disabled\", false);e.setAttribute(\"part\", \"date\");e.style.pointerEvents = null;" +
                    "})})");

        if (!this.disabledDates.isEmpty())
            getElement().executeJs("" +
                    "let array = " + jsArrayDisabled + ";\n" +
                    "document.querySelectorAll(\"vaadin-date-picker-overlay-content > vaadin-date-picker-month-scroller > div > vaadin-month-calendar\").forEach(el => {el.shadowRoot.querySelectorAll(\"#days-container > tr > td\")" +
                    ".forEach(e=>{" +
                    //"   console.log('Checking if disabled date:', e.ariaLabel);" + // Debugging statement
                    "   if (array.includes(e.ariaLabel)) {" +
                    //"       console.log('Disabling date:', e.ariaLabel);" + // Debugging statement
                    "       e.setAttribute(\"aria-disabled\", true);e.setAttribute(\"disabled\", true);e.setAttribute(\"part\", \"date disabled\");e.style.pointerEvents = \"none\";" +
                    "   } else e.setAttribute(\"aria-disabled\", false);e.setAttribute(\"disabled\", false);e.setAttribute(\"part\", \"date\");e.style.pointerEvents = null;" +
                    "})})");
    }

    private String toJSArray(List<LocalDateTime> dates) {
        String jsArray = "[";
        // TODO this breaks if DateTimePicker uses another language than english
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy, EEEE", Locale.ENGLISH);

        for (LocalDateTime d : dates) {
            String formattedDate = d.format(formatter);
            jsArray += "`" + formattedDate + "`, ";
        }

        if (jsArray.endsWith(", ")) {
            jsArray = jsArray.substring(0, jsArray.length() - 2);
        }

        jsArray += "]";
        return jsArray;
    }
}