Proposal: Add opt-in `USE_HTML5_DATE_INPUT` setting for native browser date/time pickers

Hi everyone,

I’m sorry I can’t open a topic with more than 2 links here, but it follows a detailed research that I did after the suggestion from Jacob in a ticket I opened a few weeks ago.

I created a blog article with the full explanation here on my website. Markdown version available if someone wants to update/recreate the post with all the research references.

TLDR if you don’t want to open the link to the blog post

New opt-in setting USE_HTML5_DATE_INPUT (default False) that makes DateInput, TimeInput, and DateTimeInput render native <input type="date/time/datetime-local"> instead of <input type="text">. Browser support is now ~97% globally (including Safari since 2021). It’s fully backwards-compatible: off by default, overridable per-widget, and the admin’s JS calendar gracefully defers to native pickers. Accessibility is at least on par with the existing JS widgets (which just got improved via #36459 and #36458). Main win is touch/mobile UX with platform-native pickers.

I’d appreciate feedback on the approach.

Thanks,
Denny

4 Likes

Hi!

Thanks for looking at this. For a few projects over the past 5 years, I’ve used native <input type=date> and friends, with custom widget subclasses. I think we’re ready to provide support in Django, but I’m not 100% sure on the plan to only provide a global setting that switches all forms over. Global switches are great for opting-in on new projects, but they’re not a useful tool for migrating existing codebases, where one often needs per-field control.

Additionally, BaseTemporalField (the base for DateField and friends), currently validates against locale-based formats, while <input type=date> and co. only send ISO8601 values. Your proposal has these keep working, but I think it would be best to avoid having unused parsing logic.

I think a gentler, more targeted plan would be better. The first release could do something like:

  1. Add NativeDateInput, NativeTimeInput, and NativeDateTimeInput widget classes (names to be bikeshedded).
  2. Add NativeDateField etc. that use these widgets by default.
  3. Move the admin to use them, rather than its custom widgets, with a per-ModelAdmin (?) option to switch back. (We can be more aggressive with the admin, as it’s a UI that we fully control.)
  4. Document how to use ModelFormOptions.formfield_callback to switch your forms to use the native fields.

We could also consider a global switch that changes the defaults for forms to native fields, but given there would be a snippet to copy for your base field class, that could wait for a later release, when any rough edges have been tested.

What do you think?

3 Likes

Well the main problem is keeping compatibility with the previous use case (with type="text) without breaking existing things.
I know that we can be more aggressive with the admin, but those templates can be extended as well by users, so maybe still not too aggressive :slight_smile:

I can change the implementation using different widget classes instead of the current ones, not a big problem, but then we’d have multiple classes that implement (almost) the same thing.
Referring to my current (wip)implementation I can also create those classes like:

# unchanged
class DateInput(DateTimeBaseInput):
    format_key = "DATE_INPUT_FORMATS"
    template_name = "django/forms/widgets/date.html"

# extending the base one adding html5 attributes
class NativeDateInput(DateInput):
    html5_input_type = "date"
    html5_format = "%Y-%m-%d"

so we can reuse the base logic adding the new input_type only there, or just

class NativeDateInput(DateInput):
    input_type = "date"
    html5_format = "%Y-%m-%d"

    def format_value(self, value):
        return formats.localize_input(value, "%Y-%m-%d")

Let’s see what others think, I tried to do something years ago related to this, but then there was no basic consensus and everyone “steering the wheel” on a different side, so I dropped everything because life happens :sweat_smile:

I think that now it’s time to improve this, to step into the future present