Skip to content
Cynosurev0.5.0
SearchStorybookGitHubnpmColour mode: System. Switch to Light

Components / Controls

FileDrop

A place to add files: drop them on it, or press its button to pick them. It checks each file and explains what it turned away.

Button opens the picker

When to useLink to "When to use"

  • Uploads, imports and attachments, especially where people may drag files from their desktop.

Use something else when:

UsageLink to "Usage"

tsx
Copy
import { FileDrop } from "@arshad-shah/cynosure";

<FileDrop multiple accept=".pdf,image/*" maxSize={5_000_000} hint="PDF or images, up to 5 MB" onFiles={upload} />

onFiles receives the files that passed. Without multiple only the first file is taken.

ChecksLink to "Checks"

accept (extensions, MIME types and type/*), maxSize (bytes) and maxFiles decide what is taken. Each refusal is listed in the zone and passed to onReject with its reason: type, size or count.

Checks type size and count

The whole windowLink to "The whole window"

With target="window", files dropped anywhere in the window are taken, for an app that opens whatever is dropped on it. An overlay covers the page while files are dragged in; text and links dragged over the page are left alone.

tsx
Copy
<FileDrop target="window" accept=".har,.json" onFiles={open} />

Your own picker and a list of chosen filesLink to "Your own picker and a list of chosen files"

onPick replaces the browser's file dialog with your own picker (Electron's dialog over IPC), as PathField's onPick does: the button calls it and is busy until it settles. It resolves with what was chosen, files or paths, or null when cancelled; a cancel or a failure changes nothing. Chosen files are checked like dropped ones and arrive in onFiles; chosen paths arrive in onPaths. Dropped files still arrive in onFiles.

value lists what has been chosen, files by name and paths as given, each with a remove button when onRemove is set. The list is yours: add to it from onPaths and onFiles, take out what onRemove(item, index) reports. A removal is announced, and focus moves to the next remove button, so several can be removed in a row.

tsx
Copy
const [chosen, setChosen] = useState<string[]>([]);

<FileDrop
  multiple
  value={chosen}
  onPick={() => window.api.pickFiles()} // Promise<string[] | null>
  onPaths={(paths) => setChosen([...chosen, ...paths])}
  onFiles={(files) => setChosen([...chosen, ...files.map((f) => f.name)])}
  onRemove={(_, index) => setChosen(chosen.filter((_, i) => i !== index))}
/>
Controlled list of chosen files

value is display only: a form submits the files in the native input, those picked or dropped here.

FormsLink to "Forms"

With name, the form submits the accepted files, whether they were dropped or picked: FileDrop keeps its native file input in step.

PropsLink to "Props"

Every prop of FileDrop
PropWhat it doesTypeDefault
onFiles
Called with the files that passed the checks.((files: File[]) => void)
onPick
Replaces the browser's file dialog with your picker (Electron's dialog.showOpenDialog over IPC), as PathField's onPick: the button calls it and is busy until it settles. It resolves with what was chosen, or null when it was cancelled; a cancel or a failure (the promise rejects) changes nothing. Chosen files are checked as dropped ones are and arrive in onFiles, chosen paths in onPaths. Dropped files still arrive in onFiles.(() => Promise<readonly (File | string)[] | null>)
onPaths
Called with the paths onPick chose (strings, as your picker gave them); put them in value to list them.((paths: string[]) => void)
value
The chosen files or paths, listed in the zone by name (a File's name, a path as given), each with a remove button when onRemove is set. Controlled: add to it from onFiles or your own picker. Display only: the native input (and so a form) holds only files picked or dropped here.readonly (string | File)[]
onRemove
Called with a chosen item and its index when its remove button is pressed; take it out of value.((item: File | string, index: number) => void)
onReject
Called with the files that did not, and why (they are also listed in the zone).((rejections: FileRejection[]) => void)
accept
File types, as for <input accept>: ".pdf,image/*".string
multiple
Take more than one file at a time.boolean
maxSize
Largest file in bytes.number
maxFiles
Most files in one go (with multiple).number
target
zone (default): files are dropped on the zone. window: files dropped anywhere in the window are taken, and an overlay covers the page while they are dragged in (for an app whose whole page is a drop target)."zone" | "window"
hint
Shown under the prompt, e.g. "PNG or JPG, up to 5 MB".ReactNode
name
Name the accepted files are submitted under in a form.string
form
Id of the form it belongs to, when it is not inside that form.string
required
Marks the file input as required for form validation.boolean
disabled
Turns off dropping and the button.boolean
size
Size of the zone and its button. Default "md".Size"md"
labels
Replace the built-in English text.Partial<FileDropLabels>
className
Added to the root element, for layout.string
style
Layout only. Restyle through --cy-file-drop-* tokens.CSSProperties

Generated from the type definitions in @arshad-shah/cynosure 0.5.0.

Behaviour and accessibilityLink to "Behaviour and accessibility"

  • The button is the way in. Keyboard, touch and screen reader users pick files with it; dropping is a shortcut for pointer users. The native input is hidden and out of the tab order.
  • Hint: read as the button's description.
  • Chosen files: a list named by labels.files; each remove button is named "Remove " and the item's name, and the list's rows reverse in right-to-left text.
  • Announcements: "2 files added" is announced politely; refusals are announced as an alert.
  • Dragging: the zone lights up only for files (not dragged text or links) and says "Drop to add".
  • Touch: the button's hit area is at least 44px on touch screens.
  • Contrast: the prompt and hint keep 4.5:1 in light and dark modes.
  • All built-in text is in labels.

ThemingLink to "Theming"

Tokens: --cy-file-drop-radius, --cy-file-drop-active-background, --cy-file-drop-overlay-background and --cy-file-drop-file-background (a chosen file's row).

FileInputBase · ProgressBar · Notice

These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.

Getting started
Theming
Icons
Accessibility
Code editors and highlighters
Using Cynosure without React
Build-tool adapters
Components
Accordion
AppShell
AspectRatio
Breadcrumbs
Calendar
Card
Container
Disclosure
Divider
DocumentViewport
Grid
Inline
PageHeader
PanZoomCanvas
ScrollArea
SideNav
SortableList
SplitPane
Stack
StatusBar
Tabs
TitleBar
Toolbar
Tree
VirtualList
ZoomControls
Announcer
Avatar
Badge
CodeBlock
DescriptionList
EmptyState
ErrorBoundary
Field
Heading
IconTile
Image
Kbd
List
LoadingDots
Notice
ProgressBar
Prose
Skeleton
Stat
Steps
Table
Text
Button
Checkbox
Checklist
ColorField
ColorSwatches
Combobox
CompareSlider
CopyButton
DateField
FileDrop
IconButton
KeyValueEditor
Link
NumberField
Pagination
PathField
RadioGroup
SearchField
SegmentedControl
Select
SelectionFrame
SignaturePad
Slider
Switch
TagInput
TextArea
TextField
ThemeToggle
TimeField
ButtonBase
ChoiceBase
DialogBase
FileInputBase
HiddenValue
Icon
InputBase
LinkBase
LiveRegion
TextAreaBase
ChatMessage
Choice
DataGrid
DeviceFrame
HighlightedText
HotkeyField
ListRow
OptionList
OverlayFrame
QRCode
RowActions
Section
SiteFooter
SiteHeader
SkipLink
SortButton
VisuallyHidden
CommandPalette
ContextMenu
Dialog
FloatingToolbar
HoverCard
Menu
Menubar
Popover
ProgressOverlay
Sheet
Toast
Tooltip
Changelog