webdevpuneet.com

Flatpickr Time Picker with Step Intervals — Free HTML CSS JS Snippet

Flatpickr Time Picker with Step Intervals · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

Copy & paste

Source Code

<div class="tp-wrap">
  <div class="tp-card">
    <div class="tp-title">Book a 30-Minute Slot</div>
    <label class="tp-field">Time
      <input type="text" id="tpInput" placeholder="Select a time...">
    </label>
    <div class="tp-step-group">
      <span class="tp-step-label">Interval:</span>
      <button type="button" class="tp-step active" data-step="15">15 min</button>
      <button type="button" class="tp-step" data-step="30">30 min</button>
      <button type="button" class="tp-step" data-step="60">60 min</button>
    </div>
    <div class="tp-summary" id="tpSummary">Business hours: 9:00 AM – 6:00 PM</div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Live-switchable step interval
Clean destroy-and-recreate for a construction-time-only option.
Structural business-hours limit
minTime/maxTime block out-of-range times, not just validate them.
Pure time-only mode
noCalendar strips the date grid entirely.
12-hour AM/PM format
time_24hr: false matches common booking-UI conventions.
Selection-preserving reinit
Switching intervals does not silently clear an existing pick.
Minimal, focused UI
Just the input and interval toggle, nothing extraneous.

About this UI Snippet

Flatpickr Time Picker with Step Intervals — Why Changing the Step Means Reinitializing

Screenshot of the Flatpickr Time Picker with Step Intervals snippet rendered live

A time-only picker constrained to business hours, in fixed intervals, is a common booking-flow need — but the interval itself is often something a user should be able to change (someone booking a quick call wants 15-minute granularity, someone booking a half-day block doesn't). The subtlety here isn't the picker itself, it's that Flatpickr's minute-step setting can't be changed on a live instance.

minuteIncrement is read once, at construction time

Flatpickr reads its minuteIncrement option when the instance is created and uses it to build the time UI's scroll steps — there's no supported method to change that increment on an already-running instance. Attempting to mutate fp.config.minuteIncrement directly after the fact would leave the rendered time-selector UI out of sync with the new value.

The fix is destroy-and-recreate, not a config mutation

Each step button's click handler calls fp.destroy() — Flatpickr's own cleanup method, which removes its DOM and event listeners cleanly — and then calls initPicker again with the new increment, producing a fresh instance. This is the correct, supported way to change a construction-time-only option, and it's cheap enough to do on every button click since a time-only picker's DOM is small.

enableTime plus noCalendar makes it a pure time picker

enableTime: true adds the time UI; noCalendar: true removes the date grid entirely, leaving only hour/minute/AM-PM columns — the correct combination when a flow (like this slot-booking card) already knows the date and only needs a time.

minTime and maxTime enforce business hours structurally

Rather than validating a selected time after the fact and showing an error, minTime: '09:00' and maxTime: '18:00' constrain which times are even scrollable to select in the first place — the picker can't produce an out-of-hours value at all, which is a stronger guarantee than post-hoc validation.

defaultDate carries over the previous selection where possible

When recreating the picker after a step change, defaultDate: input.value || null attempts to preserve whatever time was already typed in the input, so switching from 15-minute to 30-minute steps doesn't silently clear a selection the user already made (though the newly-selected time will snap to the new interval's nearest valid step going forward).

Reusing it

This pattern — destroy, reinitialize with new options — is the general fix any time a Flatpickr option needs to change that isn't covered by its set() API (which does support many options live); check Flatpickr's docs for which options are live-settable before reaching for a full reinit.

Step by step

How to Use

  1. 1
    Add the Flatpickr CDNLoad flatpickr.min.css and flatpickr.min.js before the snippet's JS runs.
  2. 2
    Paste HTML, CSS, and JSA time-only picker renders limited to 9 AM–6 PM.
  3. 3
    Click the time inputA scrollable time selector opens in 15-minute steps.
  4. 4
    Click "30 min" or "60 min"The picker rebuilds with the new step interval.
  5. 5
    Try scrolling past 6:00 PMTimes outside business hours are not selectable.
  6. 6
    Select a time, then change the intervalThe typed value is preserved where possible.

Real-world uses

Common Use Cases

Meeting and appointment booking
Limit selection to business hours using minTime and maxTime, blocking out-of-range values structurally instead of only visually.
Restaurant reservation times
Pair with the Flatpickr booking calendar so a date and a time are picked in a consistent style.
Service and repair scheduling
Let different job types use different step intervals, switching between 15, 30 and 60 minutes by destroying and recreating the picker cleanly.
Class and session sign-ups
Choose start times for fixed-length sessions, with noCalendar removing the date grid entirely for a pure time input.
Delivery windows and time-mode learning
Offer coarser 60-minute windows against precise 15-minute slots, and use it as a reference for 12-hour AM and PM formatting.

Got questions?

Frequently Asked Questions

Flatpickr reads minuteIncrement once when an instance is constructed and uses it to build the scrollable time UI at that point — it is not one of the options that can be changed on a live instance via Flatpickr's set() API. Calling fp.destroy() to clean up the existing instance and then creating a new one with the desired increment is the correct, supported way to apply a construction-time-only option change.

noCalendar: true tells Flatpickr not to render the date grid at all as part of its own logic, which also correctly adjusts related internal behavior (like what a selected "date" represents when only time matters). Hiding the calendar with CSS while leaving noCalendar off would leave the date grid present in the DOM and in Flatpickr's internal state, just visually hidden — a fragile approach that could cause inconsistent behavior.

Setting minTime and maxTime constrains which times are scrollable and selectable within the time picker UI itself — a user physically cannot scroll the hour or minute columns to an out-of-range value. A validation-after-selection approach would let a user pick any time first and then show an error, which is both a worse experience and leaves a window where an invalid value briefly exists in the input.

The reinitialization passes defaultDate: input.value || null, which attempts to carry over whatever value was already typed or selected in the input field when the new instance is created. The one caveat is that if the previously selected time doesn't align with the new interval's steps (e.g. a time selected at a 15-minute step being carried into a 60-minute-step picker), Flatpickr will snap it to the nearest valid step for the new increment.

Replace the fixed minTime/maxTime strings with values computed from your actual business-hours or availability data (which could vary by day of week or by resource), and re-run initPicker whenever that availability data changes, the same way the step-interval buttons already trigger a reinitialization. The destroy-and-recreate pattern applies identically regardless of what's driving the new min/max values.