Forme DS

Composants

FileInput

Le champ de téléversement du DS : sélection, glisser-déposer, statut et dropzone. Fonctionne en mode contrôlé (value/onChange) ou non-contrôlé (name pour une Server Action). Valeur : File | File[] | null.

Nouveau. En mode non-contrôlé, le composant synchronise un <input type="file"> masqué via l'API DataTransfer — Astryx n'expose pas de name. L'attribut required n'est volontairement pas posé sur l'input caché (piège de validation orpheline) : la présence du fichier se vérifie côté serveur.

Mode input (compact)

import { FileInput } from "@forme-ch/ui/controls";

<FileInput
  label="Pièce jointe"
  mode="input"
  name="piece"
  accept="application/pdf"
  placeholder="Choisir un fichier PDF"
/>

Mode dropzone

<FileInput
  label="Documents"
  mode="dropzone"
  name="docs"
  isMultiple
  accept="image/*,application/pdf"
  description="PDF ou images — 5 Mo max par fichier."
  maxSize={5 * 1024 * 1024}
/>

Contrôlé

Avec value + onChange, tu gardes la main sur la liste de fichiers (comptage, aperçus, validation).

const [files, setFiles] = useState<File | File[] | null>(null);

<FileInput
  label="Justificatifs"
  mode="dropzone"
  isMultiple
  value={files}
  onChange={setFiles}
  description={files ? "…" : "Glisse tes fichiers ici."}
/>

Props

PropTypeDéfautDescription
label * string — Libellé a11y obligatoire. Masqué visuellement si isLabelHidden.
isLabelHidden boolean false Masque visuellement le libellé (a11y conservée).
mode "input" | "dropzone" — « input » compact ou « dropzone » (grande zone glisser-déposer).
name string — Mode non-contrôlé (form / Server Action) : nom du champ FormData.
value File | File[] | null — Mode contrôlé : fichier(s) sélectionné(s).
onChange (files: File | File[] | null) => void — Appelé à chaque changement de sélection.
accept string — Types MIME acceptés (ex. application/pdf).
isMultiple boolean — Autorise plusieurs fichiers.
maxSize number — Taille max par fichier (octets).
maxFiles number — Nombre max de fichiers.
isDisabled boolean — Désactive le champ.
isRequired boolean — Champ requis (validé côté Server Action).
isLoading boolean — État de chargement (upload en cours).
description string — Texte d'aide sous le champ.
placeholder string — Texte de la zone vide.
startIcon ReactNode — Icône de tête.

Accepte aussi width, className, style et labelTooltip.

Accessibilité

label est obligatoire — c'est le nom accessible du champ, même si tu le masques visuellement avec isLabelHidden. Le description énonce les contraintes (formats, poids) et doit rester lisible. L'input masqué du mode non-contrôlé porte aria-hidden et tabIndex=-1 pour ne pas doubler la cible clavier.

Do & Don't

✓ À faire

Annoncer les formats et la taille max dans description. Valider la présence du fichier côté Server Action.

✕ À éviter

Compter sur required pour bloquer l'envoi. Masquer le label sans le renseigner.