A compact duration input with a fixed, locale-independent display for hours, minutes, seconds, and milliseconds.
Use input-duration when users need to enter a duration rather than a time of day: for example, a countdown, elapsed-time limit, or media offset. Its displayed value uses HH:mm:ss.SSS on every locale, without a locale-specific AM/PM presentation, and supports durations greater than 24 hours (currently up to 99 hours) with millisecond values, such as 30:00:00.125.
HTML's built-in <input type="time"> is for choosing a time of day, not entering elapsed time. HTML does not provide a native duration input with a fixed HH:mm:ss.SSS format or support for values over 24 hours; this web component fills that gap.
The component supplies its own segmented layout instead of the browser's native time-picker UI, so the displayed format does not change with browser or locale. It is built from native number inputs, however, so details such as the on-screen keyboard and interaction can still vary by device and browser; this is consistency of the value's presentation, not a guarantee of pixel-identical rendering. Milliseconds can be entered as three digits; the input's step controls increment in 10 ms intervals.
The control's styles are scoped inside its Shadow DOM, so global styles and resets from Tailwind or other CSS libraries do not leak into its internal layout. The control inherits its font and text color from its surrounding page.
input-duration is intended for touch and keyboard use. The HTML structure and displayed field order are controlled by the component; device-specific input and keyboard behavior remains native to the browser.
The goal is a small JavaScript duration input that gives countdowns and elapsed-time entry a predictable displayed format across browser and locale settings, while retaining native numeric inputs for editing.
Does this lose any functionality? No! document.querySelector('#bob').value has a getter and setter, so values can be set and retrieved from JavaScript or the HTML attribute.
The desktop comparisons show how a native time input represents a time of day, while input-duration displays an elapsed duration in a fixed format.
💔 the native time input on the left; 🏁 `input-duration` is shown on the right.
The mobile screenshots show the native time picker alongside input-duration on each platform.
| Device | 💔 Native time input |
🏁 input-duration |
|---|---|---|
| Android | ![]() |
![]() |
| iOS | ![]() |
![]() |
Native time inputs are useful when the user is choosing a time on a clock. A duration is different: 30:00:00.125 means thirty hours, not 6 AM the next day. Keeping those concepts separate avoids date, timezone, and 12/24-hour display concerns when collecting a duration.
Here's why:
- Enter durations independently of a calendar date or time of day.
- Keep a fixed
HH:mm:ss.SSSdisplay regardless of locale-specific clock conventions. - Represent durations beyond 24 hours (up to 99 hours in the current implementation).
- Read and set the value from JavaScript using the component's
.valueproperty.
Table of Contents
HTML's <input type="time"> represents a time of day. Browsers may localize its visible control (for example, showing a 12-hour clock with AM/PM), even though its value is standardized. It also cannot represent a duration longer than a day.
input-duration is for duration values, not appointments or clock times. Its separate numeric fields present hours, minutes, seconds, and milliseconds in a fixed HH:mm:ss.SSS format. This avoids locale-dependent time-of-day presentation while allowing durations beyond 24 hours and millisecond values in a compact control.
input-duration is a module and works with webpack. Any add-ons/plugins used in dev are in the acknowledgements section.
There are no pre-requisites for using input-duration if you're not compiling/ packaging you javascript. If you are packaging:
This is an example of how to get started with npm and webpack, other frameworks should work too.
- npm & webpack
npm install npm@latest -g npm init -y npm install webpack webpack-cli --save-dev
With packaging: This template doesn't rely on any external dependencies or services.
- Install from NPM
npm i input-duration- import input-duration in javascript
import id from 'input-duration';
Without packaging:
- Add script:
<script type="module">
import id from 'https://cdn.jsdelivr.net/npm/input-duration/+esm'
</script>
input-duration requires a <input-duration> element . There's no more HTML than that, but don't forget the closing tag. Native Input elements don't have them!
<input-duration id='bob'></input-duration>
Individual duration fields can be hidden with boolean attributes:
<input-duration no-hours no-minutes no-seconds no-microseconds></input-duration>Use hideHours(), hideMinutes(), hideSeconds(), and hideMicroSeconds() to hide fields, and the corresponding show*() methods to show them again. The existing noHours(), noMinutes(), noSeconds(), and noMicroSeconds() methods remain available as aliases for the hide*() methods. Hidden fields do not change the component's HH:mm:ss.SSS value format.
Customize the separators with the hours-divider, minutes-divider, seconds-divider, and microseconds-divider attributes. The first three replace the separators between fields; microseconds-divider adds an optional suffix after milliseconds. For example:
<input-duration hours-divider="h " minutes-divider="m " seconds-divider="s " microseconds-divider="ms"></input-duration>The equivalent methods are setHoursDivider(text), setMinutesDivider(text), setSecondsDivider(text), and setMicroSecondsDivider(text). Pass text as a string; it is rendered as text, not HTML. Remove an attribute to restore its default separator (or remove the milliseconds suffix).
If you would like to get or set values or to disable input-duration elemet, javascipt can do that:
document.querySelector('#bob').value = '44:04:04.444'
The component keeps its Shadow DOM, so Bootstrap's CSS selectors do not directly style its internal fields. Instead, map Bootstrap theme variables to the component's CSS custom properties. This is additive: without overrides, the component retains its default appearance.
input-duration {
--input-duration-border-color: var(--bs-border-color);
--input-duration-border-radius: var(--bs-border-radius);
--input-duration-background: var(--bs-body-bg);
--input-duration-color: var(--bs-body-color);
--input-duration-focus-color: var(--bs-primary);
--input-duration-focus-outline: 0.25rem solid rgba(var(--bs-primary-rgb), 0.25);
}The internal control and its fields, dividers, and icon are also exposed as Shadow Parts for targeted styling:
input-duration::part(control) {
padding: 0.375rem 0.75rem;
}
input-duration::part(field) {
font-size: 1rem;
}Available parts are control, field (also field-hours, field-minutes, field-seconds, and field-milliseconds), divider (also divider-hours-minutes, divider-minutes-seconds, and divider-seconds-milliseconds), and icon. Supported CSS custom properties are --input-duration-gap, --input-duration-padding, --input-duration-border-color, --input-duration-border-radius, --input-duration-background, --input-duration-color, --input-duration-focus-color, --input-duration-focus-outline, --input-duration-focus-outline-offset, --input-duration-divider-color, --input-duration-divider-opacity, --input-duration-disabled-color, and --input-duration-icon-color.
and
document.querySelector('#bob').disable()
so the inputs are modified.
For the generated JSDoc API reference, see the input-duration API documentation.
- Emperically determine behaviour of Input (time) on Chrome
- Reverse engineer input behaviour (arrows, digits, 0 addition, etc.)
- Cross browser/ cross os manual tests
- Add end to end multi-browser, multi-os Selinium tests
- Update demo page (either PM.com or JSfiddle type)
- Multi-language documentation (Google translate of this page?)
- Chinese
- Spanish
- Document and verify a versioned Chrome
<input type="time">behavior profile: compare the WHATWG standard with Blink's implementation and time-input tests (including multiple-field UI tests). Record Chrome version, OS, and locale; verify relevant keyboard and segment-editing behavior, then adaptinput-durationwhere appropriate without assuming platform-specific time-picker UI is universal. - Add configurable duration segments and presentation, including optional days, hiding units, and custom dividers. Keep
HH:mm:ss.SSSas the default. (html-duration-picker.js, input-duration-element) - Support declarative minimum and maximum values with consistent validation and boundary behavior. (html-duration-picker.js)
- Improve accessibility with per-segment labels, group semantics, and documented screen-reader and keyboard behavior. (time-input-polyfill demonstrates accessible time-field interactions.)
- Participate in native HTML forms, including named submission, required/validity, disabled state, and form reset/restore behavior. (duration-input example)
- Offer optional ISO 8601 duration serialization and
Temporal.Durationinteroperability without breaking the existingHH:mm:ss.SSSvalue format. (WHATWG discussion, duration-input example)
See the open issues for a full list of proposed features (and known issues).
This comparison summarizes capabilities described in each project's documentation; a dash means the feature is not documented, not necessarily unsupported. "Estimated users" is approximated by npm package downloads from 2026-10-28 through 2026-11-03, not unique people; downloads can include CI, repeated installs, and automated systems, and omit CDN or other use. The Wigny entry is a gist example rather than a maintained library, so no npm download figure is available.
| Control | Display / units | Value representation | Bounds | Precision / interaction | Estimated users* |
|---|---|---|---|---|---|
| input-duration | Fixed HH:mm:ss.SSS (00–99 hours); noHours() can hide hours |
HH:mm:ss.SSS string via .value |
No public min/max options documented | Milliseconds; digit entry, arrow navigation and increment | ~748 |
| timepoint-selection | Selectable dd:hh:mm:ss, dd:hh:mm, hh:mm:ss, hh:mm, or mm:ss; custom unit labels |
Numeric seconds through getValue() / setValue() |
Configurable maximum / rollover | Seconds; keyboard navigation, arrow increments, rollover | ~22 |
| html-duration-picker.js | HH:MM:SS; optional hidden seconds |
Formatted text in an enhanced native <input> |
Configurable minimum and maximum durations | Seconds in documented formats; interaction details not specified | ~905 |
| muan/input-duration-element | Hours, minutes, seconds; customizable dividers/slots | Numeric seconds; value and change event |
max documented; min and validation listed as TODOs |
Demo covers durations up to 180 seconds; precision beyond seconds not specified | ~9 |
| segmented-input | Duration preset or custom parsing/formatting and segments | Formatted string in an enhanced native <input> |
Per-segment min, max, and step; custom validity |
Duration preset shown to seconds; arrow-key segment navigation and adjustment | ~4 |
| Wigny duration-input example | Markup-defined hour, minute, and second segments | ISO 8601 duration string; form-associated custom element | No public min/max API documented | Fractional seconds; keyboard segment navigation and adjustment | N/A (gist) |
These projects illustrate possible directions—such as optional units, configurable formatting, bounds, alternate value formats, and native form participation—without implying that every feature is a fit for input-duration.
Potential integration targets only; these projects are not affiliated with or endorsing input-duration.
- React Hook Form — provide a tested
Controlleradapter/example that synchronizes the custom element's value, events, ref, and validation. - Formik — add a custom
Fieldexample to connect duration values to Formik-managed forms. - Angular Reactive Forms — provide a
ControlValueAccessoradapter for model-to-view updates, user changes, touched state, and disabled state. - Shoelace — document how to use the framework-agnostic duration element alongside Shoelace form controls in a consistent design system.
The browser and device results linked below are historical and should not be treated as verification against current browser versions. The local regression suite checks component behavior, but current cross-browser rendering and interaction still need to be tested.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
Run the local regression tests with npm test.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE.txt for more information.
Stephan Luis - stephan@learnsense.org
Project Link: https://github.com/StephanLuis/input-duration
Resources I've found helpful and would like to give credit to:






