Date Picker
A date picker component with range and presets.
| lu | ma | me | je | ve | sa | di |
|---|---|---|---|---|---|---|
DatePicker est un <Calendar> caché dans un popover, avec un bouton trigger qui affiche la date sélectionnée. La valeur est écrite dans un <input type="hidden" name="…"> pour être postée avec le reste du form — pas de JS custom nécessaire côté handler serveur, c'est un vrai name/value de form.
Contrat côté form :
- Single date —
name="dueDate"+value="2026-06-13"(ISO). Un seul hidden input, POST donnedueDate=2026-06-13. - Range —
mode="range"+value(début) +valueEnd(fin). Deux hidden inputs,nameetnameEnd(défaut :{name}_end). POST donnedueDate=…&dueDate_end=…. - required — pose
requiredsur le hidden ; la validation HTML5 native déclenche si vide au submit.
Comportement côté client (island ui.js) :
- Clic trigger → toggle popover (
data-ui="toggle-pop"). - Clic jour → set hidden input, met à jour le label du trigger, ferme le popover (single) ou attend la seconde date (range).
- Clic prev/next ou dropdowns mois/année → reconstruit le calendrier au nouveau mois sans reload (voir Calendar).
Options utiles : placeholder (texte quand vide), locale="fr"|"en", weekStart (0 dimanche, 1 lundi défaut), minDate/maxDate (bornes ISO), triggerWidth (largeur du bouton, défaut w-[240px]).
Installation
$ bext ui add date-picker
Usage
Anatomy
<div data-ui="date-picker" data-name="…" data-mode="single|range">
├── <input type="hidden" name="…" value="yyyy-mm-dd" />
├── <input type="hidden" name="…_end" value="…" /> // range only
├── <button data-ui="toggle-pop"> // le trigger
│ ├── <CalendarIcon /> // icône gauche
│ └── <span>{value ? formatFR(value) : placeholder}</span>
└── <div id="dp-…" data-overlay hidden> // le popover
└── <Calendar value valueEnd locale weekStart … /> // la grilleAPI Reference
DatePicker
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | — | Nom du hidden input — c'est le nom qui apparaît dans le POST du form. |
| value | string | — | Valeur ISO "yyyy-mm-dd". Le hidden input reçoit cette valeur. |
| valueEnd | string | — | Fin du range (mode="range"). Le hidden input nameEnd reçoit cette valeur. |
| nameEnd | string | {name}_end | Nom du deuxième hidden input pour le range end. |
| mode | "single" | "range" | "single" | "single" : un seul clic ferme le popover. "range" : le premier clic pose value, le second pose valueEnd. |
| placeholder | string | "Choisir une date" (fr) / "Pick a date" (en) | Texte du trigger quand vide. |
| required | boolean | — | Pose l'attribut required sur le hidden input → validation HTML5 native au submit. |
| disabled | boolean | — | Désactive le trigger. |
| id | string | dp-${name} | id du popover panel. Sert au data-target du toggle-pop. |
| locale | "fr" | "en" | "fr" | Locale pour le placeholder + le Calendar interne + le format d'affichage (dd/mm/yyyy vs yyyy-mm-dd). |
| weekStart | 0 | 1 | 1 | Voir Calendar.weekStart. |
| minDate | string | — | Borne basse ISO passée au Calendar interne. |
| maxDate | string | — | Borne haute ISO passée au Calendar interne. |
| triggerWidth | string (utility) | "w-[240px]" | Classe utility Tailwind pour la largeur du trigger button. |
| className | string | — | Classes CSS sur le wrapper root . |
Data Attributes
Attributs qu'on peut cibler en CSS custom pour override le style par état.
| Attribute | On | Values | Description |
|---|---|---|---|
| data-ui="date-picker" | root | — | Marqueur racine. |
| data-name | root | string | Reflète la prop name. |
| data-mode | root | "single" | "range" | Lu par l'island pour le comportement clic jour (fermer vs attendre le second). |
| data-locale | root | "fr" | "en" | Utilisé par l'island pour le format d'affichage post-sélection. |
| data-ui-dp-value | hidden input | — | Marqueur — l'island écrit la valeur ISO ici au clic jour. |
| data-ui-dp-end | hidden input | — | Idem pour valueEnd (mode range). |
| data-ui-dp-label | span du trigger | — | L'island met à jour le textContent avec la date formatée après clic. |
Keyboard
| Key | Action |
|---|---|
| Tab | Focus le trigger. Puis Tab intérieur : nav du Calendar. |
| Enter / Space | Sur trigger fermé : ouvre le popover. Sur bouton jour : sélectionne. |
| Escape | Ferme le popover ouvert. |
Accessibility
Le trigger est un vrai <button type="button">, focusable et activable clavier. Le popover est un <div data-overlay hidden> — l'island le passe en visible au clic, et le referme sur clic extérieur ou Escape.
La valeur est écrite dans un <input type="hidden" name="…"> — c'est un vrai champ de form. Le navigateur inclut automatiquement le hidden dans le POST ; côté serveur c'est un simple form.get("dueDate"). La validation HTML5 (required) fonctionne nativement.
Le format d'affichage post-sélection suit la locale : 13/06/2026 (fr) ou 2026-06-13 (en). La valeur ISO envoyée au serveur reste normalisée.
Pour le champ aria-label du trigger, si pas de <label for="…"> englobant, ajouter aria-label="Date d'échéance" ou similaire pour que le lecteur d'écran annonce le rôle du champ.
Examples
Vide (placeholder)
| lu | ma | me | je | ve | sa | di |
|---|---|---|---|---|---|---|
<DatePicker name="dueDate" placeholder="Choisir une date" />
En anglais
| Su | Mo | Tu | We | Th | Fr | Sa |
|---|---|---|---|---|---|---|
<DatePicker name="dueDate" value="2026-06-13" locale="en" />
Range (période)
| lu | ma | me | je | ve | sa | di |
|---|---|---|---|---|---|---|
Requis (validation HTML5)
| lu | ma | me | je | ve | sa | di |
|---|---|---|---|---|---|---|
<DatePicker name="dueDate" required placeholder="Obligatoire" />
Bornes minDate / maxDate
| lu | ma | me | je | ve | sa | di |
|---|---|---|---|---|---|---|
Trigger large
| lu | ma | me | je | ve | sa | di |
|---|---|---|---|---|---|---|
<DatePicker name="dueDate" value="2026-06-13" triggerWidth="w-[360px]" />
Edit this component live in the bext playground. The PRISM + signals version is the bext-native idiom — fine-grained reactivity, no virtual DOM.
On This Page