bêta
Time Picker <mv-time-picker>
Champ d’heure segmenté (heures, minutes, secondes optionnelles, AM/PM ordonné selon la locale via Intl) avec une liste d’heures en popover au pas choisi ; soumet toujours au format 24 heures HH:MM, associé aux formulaires.
| Catégorie | Formulaires |
|---|---|
| Type | Web Component (<mv-time-picker>) |
| Statut | bêta |
| Keywords | time-picker, timepicker, time, clock, spinbutton, segmented, listbox, popover, intl, form-associated |
When to use
- A booking form offers appointment slots every 15 or 30 minutes within opening hours
- Users type an exact time quickly, like a departure or a reminder, with arrow keys to adjust
- One time field must read as 2:30 PM in the US and 14:30 in Europe while storing the same value
Avoid when
- The field picks a calendar day, or a day and a time together → use Date Picker instead
- A touch-first flow picks a time by flicking iOS-style drums → use Wheel Picker instead
- The value is a duration like 1 h 30 min rather than a time of day → use Number Field instead
Installation
node scripts/add.mjs time-picker --out ./src/marvelousAgent IA avec le serveur MCP de Marvelous UI : install_components({ slugs: ["time-picker"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Fichiers copiés (dépendances comprises) : tokens/tokens.css, core/base.css, core/dismiss.js, core/dom.js, core/element.js, core/form.js, core/position.js, components/time-picker/time-picker.js, components/time-picker/time-picker.css.
Utilisation
Balisage de référence : partez de celui-ci et personnalisez-le avec les attributs, data-* et les variables CSS :
<form id="time-picker-demo" style="display:flex;flex-wrap:wrap;gap:1.5rem 2rem;justify-content:center;align-items:flex-start;max-width:48rem">
<div style="display:grid;gap:.4rem;width:14rem">
<label for="time-picker-demo-slot" style="font-size:.875rem;font-weight:500">Appointment</label>
<mv-time-picker id="time-picker-demo-slot" name="slot" step="30" min="09:00" max="17:30" value="10:30" required aria-describedby="time-picker-demo-slot-hint" style="--mv-time-picker-width:100%;--mv-time-picker-list-height:11rem"></mv-time-picker>
<p id="time-picker-demo-slot-hint" style="margin:0;font-size:.75rem;color:var(--mv-fg-muted)">9:00 AM to 5:30 PM, every 30 min</p>
</div>
<div style="display:grid;gap:.4rem;width:14rem">
<label for="time-picker-demo-start" style="font-size:.875rem;font-weight:500">Race start (24-hour)</label>
<mv-time-picker id="time-picker-demo-start" name="start" locale="en-GB" seconds value="14:05:30" style="--mv-time-picker-width:100%"></mv-time-picker>
<p style="margin:0;font-size:.75rem;color:var(--mv-fg-muted)">Value: <output id="time-picker-demo-start-out" style="font-family:var(--mv-font-mono)">14:05:30</output></p>
</div>
<div style="display:grid;gap:.4rem;width:14rem">
<label for="time-picker-demo-alarm" style="font-size:.875rem;font-weight:500">Wake-up alarm</label>
<mv-time-picker id="time-picker-demo-alarm" name="alarm" locale="en-US" hour-cycle="12" style="--mv-time-picker-width:100%"></mv-time-picker>
<p style="margin:0;font-size:.75rem;color:var(--mv-fg-muted)">Value: <output id="time-picker-demo-alarm-out" style="font-family:var(--mv-font-mono)">empty</output></p>
</div>
</form>
<script type="module">
const form = document.getElementById("time-picker-demo");
for (const id of ["start", "alarm"]) {
const field = form.querySelector(`#time-picker-demo-${id}`);
const out = form.querySelector(`#time-picker-demo-${id}-out`);
field.addEventListener("mv-input", (e) => { out.textContent = e.detail.value || "empty"; });
field.addEventListener("mv-change", (e) => { out.textContent = e.detail.value || "empty"; });
}
</script>API
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
value | string | 24-hour value, “HH:MM” or “HH:MM:SS”, whatever the display. Restored on form reset. | |
name | string | Form field name (submits the 24-hour value). | |
min / max | string | Earliest and latest time (“09:00”, “17:30”): bounds the list and sets rangeUnderflow / rangeOverflow. | |
step | number | 15 | Minutes between times in the list. When set explicitly, times off the grid get stepMismatch and minute arrows follow it (30: :00, :30). |
seconds | boolean | Adds a seconds segment; the value becomes “HH:MM:SS”. | |
hour-cycle | 12 | 24 | Forces a 12-hour (AM/PM) or 24-hour display; by default the locale decides. | |
locale | string | en-US | Segment order, separators, AM/PM labels, digits and list labels (Intl.DateTimeFormat). |
required | boolean | Native validation (valueMissing); a partly filled time is badInput. | |
disabled | boolean | Disables the field (a disabled fieldset does too). | |
invalid | boolean | Forces the error style and aria-invalid. | |
label | string | Accessible name without a <label for>. | |
placement | bottom-start | top-start… | bottom-start | List popover placement (flipped when there is no room). |
data-size | sm | lg | Field height. |
Properties
| Name | Type | Description |
|---|---|---|
value | string | 24-hour value, “” while empty or incomplete. |
valueAsNumber | number | Milliseconds since midnight, NaN when empty (like a native time input). |
strings | object | Overrides the default labels and messages: hour, minute, second, dayPeriod, empty, toggle, list, noTimes, missing, incomplete, underflow ({min}), overflow ({max}), step ({before}, {after}). |
hourCycleResolved | h11 | h12 | h23 | Hour cycle in use after the locale and hour-cycle are applied. |
isOpen | boolean | Whether the list is open. |
Methods
| Name | Description |
|---|---|
open() / close({ focus }) | Opens or closes the list of times. |
clear() | Empties every segment. |
focus() | Focuses the first empty segment (or the first one). |
checkValidity() / reportValidity() | Native validation. |
Events
| Name | Description |
|---|---|
mv-input | The value changed (every edit that completes or clears a time). detail: { value, hours, minutes, seconds }. |
mv-change | The value was committed: a time picked in the list, or focus leaving the field. Same detail. |
mv-open / mv-close | List opened and closed. |
CSS classes
| Name | Description |
|---|---|
mv-time-picker-field / -segments / -segment / -literal / -toggle / -popup / -list / -option | Generated parts; segments carry data-type (hour, minute, second, dayPeriod) and data-placeholder when empty. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-time-picker-width | auto | Field width. |
--mv-time-picker-radius | var(--mv-radius-md) | Field radius. |
--mv-time-picker-list-height | 15rem | Maximum height of the list before it scrolls. |
Accessibility
The field is a role=group named by the <label for> (or label). Each segment is a role=spinbutton with aria-label, aria-valuemin/max/now and aria-valuetext (“Empty” when blank), all in the tab order: ↑/↓ step (wrapping), Page ↑/↓ jump, Home/End go to the bounds, digits fill and move to the next segment, ←/→ move, Backspace clears then steps back, a/p set AM/PM. Segments are contenteditable with inputmode=numeric so phones show a number pad. The clock button (aria-haspopup=listbox, aria-expanded) or Alt+↓ opens a listbox with aria-activedescendant: ↑/↓, Page ↑/↓, Home/End, typed digits jump to a time, Enter picks, Escape closes and returns focus. Forced colors use system Highlight colors.