HextaUI

BetaGebaut auf Vercels UI SDK 0.1.0-beta.2. Die API kann sich ändern.

File input

Ein Datei-Input auf Vercels UI SDK mit Drop-Zone, Einfügen, Typ- und Größenprüfung, abgelehnten Dateien mit Gründen, Bildvorschauen und Formularunterstützung.

Abhängig von
  • @tabler/icons-react
  • @ui-sdk/core
  • @ui-sdk/react
  • class-variance-authority

Drop files here

Images or PDFs, up to 5 files of 5 MB each. You can paste them too.

import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneIcon,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputList,
  FileInputRejections,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputDemo() {
  return (
    <FileInput
      multiple
      accept={["image/*", ".pdf"]}
      maxFiles={5}
      maxSize={5_000_000}
      className="max-w-md"
    >
      <FileInputDropzone>
        <FileInputDropzoneIcon />
        <FileInputDropzoneTitle>Drop files here</FileInputDropzoneTitle>
        <FileInputDropzoneDescription>
          Images or PDFs, up to 5 files of 5 MB each. You can paste them too.
        </FileInputDropzoneDescription>
        <FileInputTrigger className="mt-3">Browse files</FileInputTrigger>
      </FileInputDropzone>
      <FileInputRejections />
      <FileInputList aria-label="Files">
        <FileInputItem />
      </FileInputList>
    </FileInput>
  )
}

export { UiSdkFileInputDemo }
pnpm dlx shadcn@latest add https://hextaui.com/r/ui-sdk-file-input.json

Fügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.

UI SDK bringt etwas eigenes CSS in einem Cascade Layer namens ui-sdk mit. Deklariere diesen Layer ganz oben im globalen Stylesheet, über dem Tailwind-Import, damit deine Klassen gewinnen.

@layer ui-sdk;

@import "tailwindcss";
import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneIcon,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputList,
  FileInputRejections,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"
<FileInput multiple accept="image/*" maxSize={5_000_000}>
  <FileInputDropzone>
    <FileInputDropzoneIcon />
    <FileInputDropzoneTitle>Drop files here</FileInputDropzoneTitle>
    <FileInputTrigger>Browse files</FileInputTrigger>
  </FileInputDropzone>
  <FileInputRejections />
  <FileInputList aria-label="Files">
    <FileInputItem />
  </FileInputList>
</FileInput>

Der Datei-Input hält die Dateien, die Leute auswählen, ablegen oder einfügen, und sendet sie mit einem Formular. Das Hochladen übernimmt deine App. FileInputItem ohne Kinder rendert eine fertige Zeile mit Vorschau, Name, Größe und Entfernen-Button, einmal pro Datei in der Liste.

Die Prüfungen für accept, Größen, Anzahl und validate laufen nur im Browser, damit Leute früh erfahren, warum eine Datei fehlt. Jeder kann sie umgehen, prüfe also jeden Upload erneut auf deinem Server.

FileInput
├── FileInputTrigger
├── FileInputDropzone
│   ├── FileInputDropzoneIcon
│   ├── FileInputDropzoneTitle
│   ├── FileInputDropzoneDescription
│   └── FileInputTrigger
├── FileInputRejections
└── FileInputList
    └── FileInputItem
        ├── FileInputItemPreview
        ├── FileInputItemContent
        │   ├── FileInputItemName
        │   └── FileInputItemSize
        └── FileInputItemRemove

accept nimmt MIME-Typen, Platzhalter und Endungen. maxFiles, minSize und maxSize setzen die Grenzen, und validate ergänzt eigene Prüfungen. FileInputRejections listet jede ausgelassene Datei mit allen Gründen, bis zur nächsten angenommenen Datei.

"use client"

import * as React from "react"

import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputList,
  FileInputRejections,
  FileInputTrigger,
  createFileInputController,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputLimits() {
  const [files] = React.useState(createFileInputController)

  return (
    <FileInput
      multiple
      controller={files}
      accept=".pdf"
      maxFiles={3}
      minSize={1}
      maxSize={2_000_000}
      validate={(file) =>
        files.getValue().some((other) => other.name === file.name)
          ? "Already added"
          : null
      }
      className="max-w-md"
    >
      <FileInputDropzone className="min-h-32">
        <FileInputDropzoneTitle>Drop up to 3 PDFs</FileInputDropzoneTitle>
        <FileInputDropzoneDescription>
          2 MB each, no empty files and no duplicates.
        </FileInputDropzoneDescription>
        <FileInputTrigger className="mt-3">Choose PDFs</FileInputTrigger>
      </FileInputDropzone>
      <FileInputRejections />
      <FileInputList aria-label="PDFs">
        <FileInputItem />
      </FileInputList>
    </FileInput>
  )
}

export { UiSdkFileInputLimits }

FileInputItemPreview zeigt ein Bild aus einer Object-URL, die es freigibt, wenn die Datei verschwindet, und für andere Typen ein Icon. Mit layout="grid" ist jede Datei eine quadratische Kachel.

import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneIcon,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputList,
  FileInputRejections,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputImages() {
  return (
    <FileInput
      multiple
      accept="image/*"
      maxFiles={6}
      maxSize={10_000_000}
      className="max-w-md"
    >
      <FileInputDropzone className="min-h-32">
        <FileInputDropzoneIcon />
        <FileInputDropzoneTitle>Add photos</FileInputDropzoneTitle>
        <FileInputDropzoneDescription>
          Up to 6 images, 10 MB each.
        </FileInputDropzoneDescription>
        <FileInputTrigger className="mt-3">Choose photos</FileInputTrigger>
      </FileInputDropzone>
      <FileInputRejections />
      <FileInputList aria-label="Photos" layout="grid">
        <FileInputItem />
      </FileInputList>
    </FileInput>
  )
}

export { UiSdkFileInputImages }

Ein Auslöser allein öffnet die Dateiauswahl des Systems. Ohne multiple ersetzt eine neue Datei die aktuelle, und die Kinder der Wurzel können eine Funktion ihres Zustands sein.

"use client"

import { IconUpload } from "@tabler/icons-react"

import { FileInput, FileInputTrigger } from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputButton() {
  return (
    <FileInput accept=".pdf,.doc,.docx">
      {(state) => (
        <div className="flex min-w-0 items-center gap-3">
          <FileInputTrigger>
            <IconUpload aria-hidden="true" />
            {state.value[0] ? "Replace resume" : "Upload resume"}
          </FileInputTrigger>
          <span className="min-w-0 truncate text-sm text-muted-foreground">
            {state.value[0]?.name ?? "No file chosen"}
          </span>
        </div>
      )}
    </FileInput>
  )
}

export { UiSdkFileInputButton }

Mit variant="composer" ist die Drop-Zone die Karte um ein Nachrichtenfeld, und layout="chips" listet Dateien als kompakte Chips. pasteTarget nimmt eingefügte Screenshots aus dem Textfeld, eingefügter Text bleibt Text.

"use client"

import * as React from "react"
import { IconArrowUp, IconPaperclip } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"
import {
  FileInput,
  FileInputDropzone,
  FileInputItem,
  FileInputList,
  FileInputRejections,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputAttachments() {
  const message = React.useRef<HTMLTextAreaElement>(null)

  return (
    <FileInput multiple maxFiles={4} maxSize={20_000_000} className="max-w-lg">
      <FileInputDropzone
        variant="composer"
        pasteTarget={() => message.current}
      >
        <FileInputList aria-label="Attachments" layout="chips">
          <FileInputItem />
        </FileInputList>
        <textarea
          ref={message}
          aria-label="Message"
          placeholder="Ask anything, or paste a screenshot"
          rows={2}
          className="field-sizing-content max-h-40 min-h-12 w-full resize-none bg-transparent px-2 py-1.5 text-sm outline-none placeholder:text-muted-foreground pointer-coarse:text-touch"
        />
        <div className="flex items-center justify-between">
          <FileInputTrigger
            variant="ghost"
            size="icon-sm"
            aria-label="Attach files"
          >
            <IconPaperclip aria-hidden="true" />
          </FileInputTrigger>
          <Button type="button" size="icon-sm" shape="pill" aria-label="Send">
            <IconArrowUp aria-hidden="true" />
          </Button>
        </div>
      </FileInputDropzone>
      <FileInputRejections />
    </FileInput>
  )
}

export { UiSdkFileInputAttachments }

Mit target="document" und variant="overlay" bedeckt die Zone die Seite, solange Dateien über das Fenster gezogen werden, und nimmt überall abgelegte Dateien. Was auf einer anderen Zone landet, bleibt dort.

import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneIcon,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputList,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputPageDrop() {
  return (
    <FileInput multiple className="max-w-md">
      <div className="flex items-center justify-between gap-3">
        <p className="m-0 text-sm text-muted-foreground">
          Drop files anywhere on this page.
        </p>
        <FileInputTrigger>Upload files</FileInputTrigger>
      </div>
      <FileInputDropzone target="document" variant="overlay">
        <FileInputDropzoneIcon />
        <FileInputDropzoneTitle>Drop to attach</FileInputDropzoneTitle>
        <FileInputDropzoneDescription>
          Files land in the list below.
        </FileInputDropzoneDescription>
      </FileInputDropzone>
      <FileInputList aria-label="Attachments">
        <FileInputItem />
      </FileInputList>
    </FileInput>
  )
}

export { UiSdkFileInputPageDrop }

directory wählt einen ganzen Ordner und schaltet multiple ein. Eintragsnamen zeigen den Pfad im Ordner.

import { IconFolder } from "@tabler/icons-react"

import {
  FileInput,
  FileInputItem,
  FileInputList,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputFolders() {
  return (
    <FileInput directory className="max-w-md">
      <FileInputTrigger className="self-start">
        <IconFolder aria-hidden="true" />
        Choose a folder
      </FileInputTrigger>
      <div className="max-h-72 overflow-y-auto overscroll-contain p-1 empty:hidden">
        <FileInputList aria-label="Folder contents">
          <FileInputItem />
        </FileInputList>
      </div>
    </FileInput>
  )
}

export { UiSdkFileInputFolders }

Übergib value und onValueChange. Ein Controller aus createFileInputController() öffnet die Auswahl von jedem Button aus und leert oder ergänzt Dateien.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  FileInput,
  FileInputItem,
  FileInputList,
  createFileInputController,
  formatFileSize,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputControlled() {
  const [files, setFiles] = React.useState<File[]>([])
  const [picker] = React.useState(createFileInputController)
  const total = files.reduce((sum, file) => sum + file.size, 0)

  return (
    <div className="flex w-full max-w-md flex-col gap-3">
      <div className="flex flex-wrap items-center gap-2">
        <Button size="sm" variant="outline" onClick={() => picker.open()}>
          Choose files
        </Button>
        <Button
          size="sm"
          variant="ghost"
          disabled={files.length === 0}
          onClick={() => picker.clear()}
        >
          Clear
        </Button>
        <span className="ms-auto text-sm text-muted-foreground tabular-nums">
          {files.length === 0
            ? "No files"
            : `${files.length} ${files.length === 1 ? "file" : "files"}, ${formatFileSize(total)}`}
        </span>
      </div>
      <FileInput
        multiple
        controller={picker}
        value={files}
        onValueChange={(value) => setFiles(value)}
      >
        <FileInputList aria-label="Chosen files">
          <FileInputItem />
        </FileInputList>
      </FileInput>
    </div>
  )
}

export { UiSdkFileInputControlled }

Mit einem name werden die Dateien über einen nativen Datei-Input gesendet, sogar bevor die Seite hydriert. Abgelehnte Dateien werden nie gesendet, und ein Formular-Reset leert die Liste.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputList,
  FileInputRejections,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputForm() {
  const [submitted, setSubmitted] = React.useState<string[] | null>(null)

  return (
    <form
      className="flex w-full max-w-md flex-col gap-3"
      onSubmit={(event) => {
        event.preventDefault()
        const data = new FormData(event.currentTarget)
        setSubmitted(
          data
            .getAll("attachments")
            .flatMap((entry) =>
              entry instanceof File && entry.name ? [entry.name] : []
            )
        )
      }}
      onReset={() => setSubmitted(null)}
    >
      <FileInput name="attachments" multiple maxSize={10_000_000}>
        <FileInputDropzone className="min-h-32">
          <FileInputDropzoneTitle>Attach files</FileInputDropzoneTitle>
          <FileInputDropzoneDescription>
            Up to 10 MB each.
          </FileInputDropzoneDescription>
          <FileInputTrigger className="mt-3">Browse files</FileInputTrigger>
        </FileInputDropzone>
        <FileInputRejections />
        <FileInputList aria-label="Attachments">
          <FileInputItem />
        </FileInputList>
      </FileInput>
      <div className="flex items-center gap-3">
        <Button type="submit" size="sm">
          Submit
        </Button>
        <Button type="reset" size="sm" variant="ghost">
          Reset
        </Button>
      </div>
      <p className="m-0 text-sm text-muted-foreground">
        {submitted === null
          ? "Nothing submitted yet."
          : submitted.length
            ? `Submitted ${submitted.join(", ")}`
            : "Submitted with no files."}
      </p>
    </form>
  )
}

export { UiSdkFileInputForm }

invalid markiert Drop-Zone und Auslöser, und der Auslöser meldet es Screenreadern. Richte aria-describedby des Auslösers auf deine Meldung.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputList,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputInvalid() {
  const [invalid, setInvalid] = React.useState(false)
  const errorId = React.useId()

  return (
    <form
      noValidate
      className="flex w-full max-w-md flex-col gap-3"
      onSubmit={(event) => {
        event.preventDefault()
        const data = new FormData(event.currentTarget)
        const proof = data.get("proof")
        setInvalid(!(proof instanceof File && proof.name))
      }}
    >
      <FileInput
        name="proof"
        accept={["image/*", ".pdf"]}
        invalid={invalid}
        onValueChange={(value) => {
          if (value.length) setInvalid(false)
        }}
      >
        <FileInputDropzone className="min-h-32">
          <FileInputDropzoneTitle>Proof of address</FileInputDropzoneTitle>
          <FileInputDropzoneDescription>
            A utility bill or bank statement from the last 3 months.
          </FileInputDropzoneDescription>
          <FileInputTrigger
            className="mt-3"
            aria-describedby={invalid ? errorId : undefined}
          >
            Choose a file
          </FileInputTrigger>
        </FileInputDropzone>
        {invalid ? (
          <p id={errorId} className="m-0 text-sm text-destructive">
            Add a scan to continue.
          </p>
        ) : null}
        <FileInputList aria-label="Proof of address">
          <FileInputItem />
        </FileInputList>
      </FileInput>
      <Button type="submit" size="sm" className="self-start">
        Continue
      </Button>
    </form>
  )
}

export { UiSdkFileInputInvalid }

Ein deaktivierter Datei-Input ignoriert Auswahl, Ablegen und Einfügen und sendet nichts.

import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneIcon,
  FileInputDropzoneTitle,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputDisabled() {
  return (
    <FileInput disabled className="max-w-md">
      <FileInputDropzone>
        <FileInputDropzoneIcon />
        <FileInputDropzoneTitle>Uploads are paused</FileInputDropzoneTitle>
        <FileInputDropzoneDescription>
          Drops and pastes are ignored while the file input is disabled.
        </FileInputDropzoneDescription>
        <FileInputTrigger className="mt-3">Browse files</FileInputTrigger>
      </FileInputDropzone>
    </FileInput>
  )
}

export { UiSdkFileInputDisabled }

Zeilen und Drop-Zone werden gespiegelt, Dateinamen behalten ihre eigene Richtung, und Größen werden im übergebenen Locale formatiert.

"use client"

import {
  FileInput,
  FileInputDropzone,
  FileInputDropzoneDescription,
  FileInputDropzoneIcon,
  FileInputDropzoneTitle,
  FileInputItem,
  FileInputItemContent,
  FileInputItemName,
  FileInputItemPreview,
  FileInputItemRemove,
  FileInputItemSize,
  FileInputList,
  FileInputTrigger,
} from "@/components/ui/ui-sdk-file-input"

function UiSdkFileInputRtl() {
  return (
    <div dir="rtl" className="w-full max-w-md">
      <FileInput multiple accept="image/*">
        <FileInputDropzone className="min-h-32">
          <FileInputDropzoneIcon />
          <FileInputDropzoneTitle>أفلت الصور هنا</FileInputDropzoneTitle>
          <FileInputDropzoneDescription>
            أو الصقها من الحافظة.
          </FileInputDropzoneDescription>
          <FileInputTrigger className="mt-3">تصفح الملفات</FileInputTrigger>
        </FileInputDropzone>
        <FileInputList aria-label="الصور">
          <FileInputItem>
            {({ file }) => (
              <>
                <FileInputItemPreview />
                <FileInputItemContent>
                  <FileInputItemName />
                  <FileInputItemSize locale="ar" />
                </FileInputItemContent>
                <FileInputItemRemove aria-label={`إزالة ${file.name}`} />
              </>
            )}
          </FileInputItem>
        </FileInputList>
      </FileInput>
    </div>
  )
}

export { UiSdkFileInputRtl }
TasteAktion
TabSpringt zum Auslöser, dann in die Liste, auf die zuletzt fokussierte oder die erste Datei.
EnterSpaceÖffnet die Dateiauswahl vom Auslöser aus.
↑↓←→Wechselt zwischen den Dateien der Liste.
HomeEndSpringt zur ersten oder letzten Datei.
DeleteBackspaceEntfernt die fokussierte Datei und fokussiert die nächste.
⌘VFügt Dateien ein, solange der Fokus in der Drop-Zone oder ihrem Einfügeziel liegt.

Die Drop-Zone ist kein Bedienelement, also gehört immer ein Auslöser daneben, für Leute mit Tastatur oder Screenreader. Die Liste ist ein Tab-Stopp, jeder Entfernen-Button ist nach seiner Datei benannt, etwa „Remove photo.png“, und bleibt außerhalb der Tab-Reihenfolge, weil Entf auf dem Eintrag dasselbe tut.

Angenommene, entfernte und abgelehnte Dateien werden über eine höfliche Live-Region auf Englisch angesagt. Übergib announcement, um es in deiner Sprache zu sagen, und getReasonLabel an FileInputRejections für die Gründe. Das Drop-Zonen-Icon hebt sich nur, wenn Bewegung erlaubt ist, und nur dann blenden neue Zeilen ein.

Jeder Teil umhüllt den gleichnamigen UI-SDK-Teil und nimmt alle seine Props an, auch render und einen className, der eine Funktion des Zustands sein kann.

PropTypStandard
value
File[]–
defaultValue
File[][]
onValueChangedetails enthält den Grund und die hinzugefügten, entfernten und abgelehnten Dateien.
(value: File[], details) => void–
onRejectLäuft, wenn Dateien die Prüfungen nicht bestehen, auch wenn keine angenommen wurde.
(rejected: FileRejection[], details) => void–
accept
string | string[]–
multiple
booleanfalse
maxFiles
number–
maxSizeIn Bytes.
number–
minSizeIn Bytes.
number–
validateGib einen Grund zurück, um die Datei abzulehnen, nach den eingebauten Prüfungen.
(file: File) => string | null–
directory
booleanfalse
captureÖffnet auf Smartphones die Kamera.
"user" | "environment" | boolean–
invalid
booleanfalse
disabled
booleanfalse
required
booleanfalse
name
string–
form
string–
announcementWas Screenreader nach einer Änderung hören.
(change) => string | null–
controllerAus createFileInputController().
FileInputController–
children
ReactNode | (state) => ReactNode–
AttributBeschreibung
data-slot="file-input"Spricht den Datei-Input in CSS an.
data-draggingVorhanden, solange Dateien über eine seiner Drop-Zonen gezogen werden.
data-invalidVorhanden, wenn ungültig.
data-requiredVorhanden, wenn eine Datei Pflicht ist.
data-disabledVorhanden, wenn deaktiviert.
PropTypStandard
variantEine gestrichelte Zone, eine Karte um einen Nachrichten-Editor oder ein ganzseitiges Overlay, das beim Ziehen erscheint.
"default" | "composer" | "overlay""default"
target
"element" | "document""element"
pasteTargetEin weiterer Ort, von dem eingefügte Dateien kommen.
"document" | string | Element | () => Element–
render
ReactElement | (props, state) => ReactElement–
AttributBeschreibung
data-slot="file-input-dropzone"Spricht die Drop-Zone in CSS an.
data-variantDie Variante: default, composer oder overlay.
data-draggingVorhanden, solange Dateien darüber gezogen werden.
data-drag-acceptVorhanden, solange die gezogenen Dateien nach Typ und Anzahl annehmbar aussehen.
data-drag-rejectVorhanden, solange eine gezogene Datei einen nicht angenommenen Typ hat oder es zu viele sind.
data-disabledVorhanden, wenn deaktiviert.
PropTypStandard
variant
Button variant"outline"
size
Button size"sm"
controllerVerbindet einen Auslöser außerhalb des Datei-Inputs, etwa einen in einer Toolbar.
FileInputController–
render
ReactElement | (props, state) => ReactElement–
PropTypStandard
layoutZeilen, quadratische Bildkacheln oder kompakte Chips. Einträge übernehmen ihr Aussehen daraus.
"list" | "grid" | "chips""list"
render
ReactElement | (props, state) => ReactElement–
AttributBeschreibung
data-slot="file-input-list"Spricht die Liste in CSS an.
data-layoutDas Layout: list, grid oder chips. Einträge tragen es ebenfalls.
PropTypStandard
childrenStandardmäßig Vorschau, Name, Größe und Entfernen-Button. Der Zustand enthält die Datei und ihren Index.
ReactNode | (state) => ReactNode–
render
ReactElement | (props, state) => ReactElement–
AttributBeschreibung
data-slot="file-input-item"Spricht die Zeile einer Datei in CSS an.
data-disabledVorhanden, wenn deaktiviert.
AttributBeschreibung
data-slot="file-input-item-preview"Spricht die Vorschau in CSS an.
data-kindimage für eine Bildvorschau, icon für ein Icon nach Dateityp.
PropTypStandard
localeFormatiert die Größe, etwa 2.4 kB, in diesem Locale. Standard ist das des Browsers.
string–
PropTypStandard
childrenStandardmäßig ein X-Icon.
ReactNode–
render
ReactElement | (props, state) => ReactElement–
PropTypStandard
getReasonLabelBenennt jeden Grund. Standardmäßig auf Englisch, etwa „Larger than 5 MB“.
(reason, rules, rejection) => string–
AttributBeschreibung
data-slot="file-input-rejections"Spricht die Liste abgelehnter Dateien in CSS an.