Field
Des libellés, descriptions et erreurs reliés à leur contrôle, avec états de validation et mises en page pour les formulaires.
pnpm dlx shadcn@latest add https://hextaui.com/r/field.jsonAjoute le composant, les tokens de thème HextaUI et les composants HextaUI dont il dépend.
Ajoutez les tokens de thème à votre CSS global, si ce n’est pas déjà fait.
Installez les dépendances.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopiez et collez le code suivant dans votre projet.
components/ui/field.tsx components/ui/input.tsx components/ui/number-flow.tsx components/ui/separator.tsx lib/motion.ts Mettez à jour les chemins d’import selon la configuration de votre projet.
Placez n’importe quel contrôle HextaUI dans un <Field /> et il est automatiquement étiqueté, décrit et validé. Inutile de câbler id, htmlFor ou aria-describedby à la main.
Un contrôle avec son libellé, son texte d’aide et sa validation.
Un interrupteur ou une case à cocher avec son texte à côté.
Un libellé qui enveloppe tout un champ, pour que la carte soit la cible du clic.
Champs liés, espacés uniformément.
Un groupe de champs avec titre, ou un groupe radio ou de cases à cocher avec un élément par option.
Input
Un libellé, un contrôle et une description. Cliquer sur le libellé donne le focus au champ, et les lecteurs d’écran lisent la description après le libellé.
Validation
Les contraintes natives comme required et minLength sont vérifiées au blur. Donnez à chaque <FieldError /> un match pour formuler le message selon le problème. Un champ requis vide n’est signalé qu’après avoir été modifié : le franchir par tabulation ne déclenche donc pas d’alerte.
Validation personnalisée
Passez validate pour vérifier n’importe quoi, y compris des recherches asynchrones. Retournez un message pour échouer ou rien pour réussir. Avec validationMode="onChange" et validationDebounceTime, elle s’exécute pendant la saisie sans se déclencher à chaque touche. Essayez « ada ».
Requis et facultatif
Définissez indicator sur un FieldGroup, FieldSet ou Field et chaque libellé à l’intérieur se marque d’après l’attribut required de son contrôle. "optional" signale les champs que l’on peut ignorer, ce qui paraît plus calme quand la plupart des champs sont requis. "required" ajoute un astérisque. La marque est masquée aux lecteurs d’écran, car le contrôle l’annonce déjà.
Statut
<FieldStatus /> dessine une coche lorsqu’un champ modifié passe la validation, et affiche une icône d’alerte tant qu’elle échoue. Il suit le validationMode du champ et ne juge donc jamais un champ avant l’exécution de la validation.
Compteur de caractères
<FieldCounter /> trouve le contrôle de texte de son champ et compte par rapport à son maxLength. Il ne fait qu’écouter : la saisie n’est jamais ralentie ni modifiée.
Erreurs d’une bibliothèque de formulaires ou du serveur
Passez invalid au champ et un tableau errors à <FieldError />. Il accepte la forme { message } que renvoient React Hook Form et la plupart des bibliothèques de schémas. Les doublons sont supprimés, et plusieurs messages deviennent une liste. Lorsque les messages changent, les nouveaux apparaissent en fondu et la hauteur s’adapte en douceur : rien en dessous ne saute. Soumettez à vide, puis corrigez une règle à la fois.
Cases à cocher
Utilisez orientation="horizontal" pour placer la case à cocher à côté de son libellé. Dans un <FieldSet />, la légende nomme tout le groupe.
Cartes de choix
Enveloppez tout un champ dans <FieldLabel /> pour que la carte soit la cible du clic. Utilisez <FieldTitle /> à l’intérieur, car les labels ne peuvent pas s’imbriquer. La carte se teinte lorsqu’elle est cochée et affiche l’anneau de focus lorsque sa case à cocher a le focus.
Fieldset
<FieldSet /> regroupe des champs liés sous un <FieldLegend />, qui devient le nom accessible du groupe. Disposez les champs côte à côte avec une simple grille.
Responsive
orientation="responsive" empile le libellé et le contrôle dans les espaces étroits et les place côte à côte dès que le <FieldGroup /> environnant est assez large. Il réagit à la largeur du groupe, pas à celle de la fenêtre.
Désactivé
Désactiver un <FieldSet /> désactive chaque champ et contrôle à l’intérieur. Passez disabled à un seul <Field /> pour ne désactiver que celui-là.
Contenu long
Les libellés, descriptions et erreurs passent à la ligne dans les formulaires étroits, y compris les chaînes sans coupure, et n’élargissent jamais la mise en page.
De droite à gauche
Le texte, la position des cases à cocher et les listes d’erreurs suivent le sens de lecture.
- Le libellé, la description et les erreurs visibles sont reliés au contrôle pour vous : les lecteurs d’écran annoncent donc les trois lorsqu’il reçoit le focus.
- Les contrôles invalides reçoivent
aria-invalid, qui dessine aussi leur anneau d’erreur. - Les erreurs ne sont pas des régions live. Elles sont lues lorsque le contrôle reçoit le focus : valider à chaque changement n’interrompt donc pas la saisie. À la soumission, déplacez le focus vers le premier champ invalide.
- Les erreurs grandissent et apparaissent en fondu sur place au lieu de repousser le contenu. Avec la réduction des animations, elles apparaissent sans animation.
Construit sur le field et le fieldset de Base UI. Chaque partie accepte les props de l’élément ou de la primitive qu’elle rend.
| Prop | Type | Par défaut |
|---|---|---|
orientation | "vertical" | "horizontal" | "responsive" | "vertical" |
indicatorMarque le libellé d’après l’attribut required du contrôle. Hérité de FieldGroup ou FieldSet. | "required" | "optional" | null | – |
nameIdentifie le champ lors de la soumission du formulaire. | string | – |
validateRetournez un ou plusieurs messages pour échouer, ou rien pour réussir. L’asynchrone est pris en charge. | (value, formValues) => string | string[] | null | Promise<…> | – |
validationMode | "onSubmit" | "onBlur" | "onChange" | "onSubmit" |
validationDebounceTimeMillisecondes d’attente entre les validations onChange. | number | 0 |
invalidÀ définir depuis une bibliothèque de formulaires ou une réponse du serveur. | boolean | – |
disabled | boolean | false |
dirty | boolean | – |
touched | boolean | – |
actionsRefValide le champ de façon impérative. | RefObject<{ validate: () => void }> | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Description |
|---|---|
data-slot="field" | Ciblez les champs en CSS. |
data-orientation | L’orientation actuelle. |
data-disabled | Présent lorsque le champ est désactivé. |
data-valid | Présent lorsque le champ est valide. |
data-invalid | Présent lorsque le champ est invalide. |
data-dirty | Présent une fois que la valeur a changé par rapport à sa valeur initiale. |
data-touched | Présent une fois que le contrôle a reçu puis perdu le focus. |
data-filled | Présent lorsque le contrôle a une valeur. |
data-focused | Présent tant que le contrôle a le focus. |
| Prop | Type | Par défaut |
|---|---|---|
nativeLabelÀ définir sur false lorsque render remplace le libellé par un élément qui n’est pas un label. | boolean | true |
optionalTextTexte affiché avec indicator="optional". | ReactNode | "Optional" |
render | ReactElement | (props, state) => ReactElement | <label> |
| Attribut | Description |
|---|---|
data-slot="field-label" | Ciblez les libellés en CSS. En dehors d’un champ, il rend un label simple, ce qui fait fonctionner les cartes de choix. |
data-disabled | Présent lorsque le champ est désactivé. |
data-valid | Présent lorsque le champ est valide. |
data-invalid | Présent lorsque le champ est invalide. |
data-dirty | Présent une fois que la valeur a changé par rapport à sa valeur initiale. |
data-touched | Présent une fois que le contrôle a reçu puis perdu le focus. |
data-filled | Présent lorsque le contrôle a une valeur. |
data-focused | Présent tant que le contrôle a le focus. |
Une icône qui reflète la validité du champ. Elle est décorative, car le message d’erreur porte le sens.
| Attribut | Description |
|---|---|
data-slot="field-status" | Ciblez l’icône de statut en CSS. |
| Prop | Type | Par défaut |
|---|---|---|
threshold | number | 10% of maxLength, at most 20 |
announcementMessage pour les lecteurs d’écran lorsque le compteur franchit le seuil ou atteint la limite. | (remaining: number) => string | – |
| Attribut | Description |
|---|---|
data-slot="field-counter" | Ciblez le compteur en CSS. |
data-state="near" | "limit" | Présent dans le seuil, et à la limite. |
| Prop | Type | Par défaut |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <p> |
| Attribut | Description |
|---|---|
data-slot="field-description" | Ciblez les descriptions en CSS. |
data-disabled | Présent lorsque le champ est désactivé. |
data-valid | Présent lorsque le champ est valide. |
data-invalid | Présent lorsque le champ est invalide. |
data-dirty | Présent une fois que la valeur a changé par rapport à sa valeur initiale. |
data-touched | Présent une fois que le contrôle a reçu puis perdu le focus. |
data-filled | Présent lorsque le contrôle a une valeur. |
data-focused | Présent tant que le contrôle a le focus. |
| Prop | Type | Par défaut |
|---|---|---|
matchN’affiche que pour ce problème de validité. true l’affiche toujours. | boolean | "valueMissing" | "typeMismatch" | "tooShort" | "tooLong" | "patternMismatch" | "rangeOverflow" | "rangeUnderflow" | "stepMismatch" | "badInput" | "customError" | "valid" | – |
errorsErreurs d’une bibliothèque de formulaires ou du serveur. Affichées lorsque la liste contient un message. | Array<{ message?: string } | undefined> | – |
childrenPar défaut, le message de validation. | ReactNode | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Description |
|---|---|
data-slot="field-error" | Ciblez les erreurs en CSS. |
data-starting-style | Présent pendant que l’erreur apparaît. |
data-ending-style | Présent pendant que l’erreur se replie. |
data-disabled | Présent lorsque le champ est désactivé. |
data-valid | Présent lorsque le champ est valide. |
data-invalid | Présent lorsque le champ est invalide. |
data-dirty | Présent une fois que la valeur a changé par rapport à sa valeur initiale. |
data-touched | Présent une fois que le contrôle a reçu puis perdu le focus. |
data-filled | Présent lorsque le contrôle a une valeur. |
data-focused | Présent tant que le contrôle a le focus. |
Empile un libellé, une description et une erreur à côté d’un contrôle dans un champ horizontal.
| Prop | Type | Par défaut |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
Un titre au style de libellé pour le contenu d’un <FieldLabel />, comme des cartes de choix.
| Prop | Type | Par défaut |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
Espace les champs et constitue le conteneur que mesurent les champs responsives.
| Prop | Type | Par défaut |
|---|---|---|
indicatorS’applique à chaque champ à l’intérieur. | "required" | "optional" | null | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Prop | Type | Par défaut |
|---|---|---|
indicatorS’applique à chaque champ à l’intérieur. | "required" | "optional" | null | – |
disabledDésactive chaque champ à l’intérieur. | boolean | false |
render | ReactElement | (props, state) => ReactElement | <fieldset> |
| Attribut | Description |
|---|---|
data-slot="field-set" | Ciblez les fieldsets en CSS. |
data-disabled | Présent lorsque le fieldset est désactivé. |
| Prop | Type | Par défaut |
|---|---|---|
variantlabel correspond à la taille d’un libellé de champ. | "legend" | "label" | "legend" |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Description |
|---|---|
data-slot="field-legend" | Ciblez les légendes en CSS. |
data-variant | La variante actuelle. |
Un <Separator /> espacé pour les formulaires, qui accepte toutes ses props.
| Prop | Type | Par défaut |
|---|---|---|
childrenTexte facultatif affiché au milieu de la ligne. | ReactNode | – |
alignOù le texte se place le long de la ligne. | "start" | "center" | "end" | "center" |
decorativeMasque une ligne simple aux lecteurs d’écran lorsqu’elle est purement visuelle. | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Description |
|---|---|
data-slot="field-separator" | Ciblez les séparateurs de champs en CSS. |
data-content | Présent lorsque le séparateur contient du texte. |
data-slot="separator-label" | L’élément qui enveloppe le texte. |
Enveloppe une case à cocher ou un radio et son libellé dans un groupe, pour que chaque élément puisse être désactivé séparément.
| Prop | Type | Par défaut |
|---|---|---|
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
Rend n’importe quoi à partir de l’état de validité du champ, par exemple un indicateur de robustesse ou un compteur de caractères.
| Prop | Type | Par défaut |
|---|---|---|
children | (state: { validity, errors, error, value }) => ReactNode | – |
- InputUn champ de saisie texte en trois tailles, avec états invalide et lecture seule, style de validation natif et police tactile de 16px pour que les téléphones ne zooment jamais.
- MotionLes courbes d’easing, les durées et la vérification de réduction des animations utilisées par chaque composant, ainsi que des hooks pour les morphs de taille et les surlignages glissants.
- SeparatorUn trait fin qui sépare le contenu horizontalement ou verticalement, avec un libellé facultatif et un mode décoratif pour les lignes purement visuelles.
- useComposedRefConserve une ref vers votre propre élément tout en la transmettant à la ref passée par le parent.
- useMergedRefCombine un nombre quelconque de refs callback et objet en une seule, avec le nettoyage de ref de React 19 pour chacune.
- CalendarUne grille de dates pour la sélection simple, de plage et multiple, avec des mois qui défilent, des aperçus de plage et des jours à taille tactile.
Utilisé dans les blocks
Des blocks qui s’appuient sur Field.
- API keysLa page des clés d’API d’un produit d’IA, comme les consoles d’OpenAI et d’Anthropic. Créez des clés avec des permissions limitées et une expiration, voyez le secret une seule fois avec une copie qui confirme, révoquez avec annulation, renommez sur place, effectuez une rotation avec période de grâce et consultez l’utilisation par clé.
- BillingForfait et utilisation pour un produit d’IA, dans le style de Cursor, Claude et Vercel. Un compteur d’utilisation réparti par modèle qui projette la fin du cycle et prévient avant la fin des crédits, un graphique quotidien explorable, une limite de dépenses avec des alertes prévisualisables sur le compteur, des changements de forfait avec proratisation exacte, un formulaire de carte avec une vraie validation, et des factures téléchargeables en PDF.
- ModelsLa page Modèles des paramètres d’un produit d’IA. Un modèle par défaut avec son contexte, sa vitesse et son coût en un coup d’œil, un effort par défaut qui sait ce que prend en charge chaque modèle, une liste de modèles consultable groupée par fournisseur avec filtres, épingles et bascules groupées, des serveurs compatibles OpenAI avec un vrai test de connexion, et une actualisation qui indique les nouveautés.
- NotificationsLa section Notifications des paramètres d’un produit d’IA. Une grille canal par événement avec bascules par ligne, par colonne et globale, des heures calmes avec une ligne « prochain calme » en direct, un résumé par e-mail, de vrais envois de test pour le bureau, l’e-mail, le push et Slack, la gestion des permissions du navigateur et un flux de connexion à Slack. S’intègre dans n’importe quelle section Settings.