Dropzone
- Needs review
- WCAG 2.2 evidence
- RTL
An area to drop files on, with a Browse button that opens the file picker. Built on React Aria DropZone
and FileTrigger. Dragging is an enhancement: Browse is a real button reached with Tab and activated with Enter or Space
(WCAG 2.1.1, 2.5.7), and pasting files works while the drop target has keyboard focus. The drop target is named by the title
and the helper; drag-over, the helper and errors are announced through polite live regions (4.1.3). Errors show an icon and
text, not colour alone (1.4.1, 3.3.1). Upload logic stays in your app: onSelect receives File objects; show progress with FileItem. Consumer duties: title and helper wording (accepted types and size), error wording, size checks, and announcing what happens
to the files (FileItem announces completion and errors).
import { Dropzone } from "@nexera-ui/react";- 5
- examples
- 17
- props
- 7
- live controls
- 1
- platform
- 12
- WCAG criteria
- 2
- blocks use it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { Dropzone } from "@nexera-ui/react";
<Dropzone />Examples 4
The same examples as Storybook, rendered live. Open Code to copy one.
Compact
Figma Layout=Compact: one row for tight spaces; the Browse button wraps under the text in narrow containers.
import { Dropzone } from "@nexera-ui/react";
<Dropzone
title="Drag files here or browse"
description="PDF, JPG or PNG up to 10 MB"
acceptedFileTypes={["application/pdf", "image/jpeg", "image/png"]}
/>;
States
Semantic states: isInvalid with errorMessage and isDisabled.
import { Dropzone } from "@nexera-ui/react";
export function States() {
return (
<div className="flex flex-col gap-6">
<Dropzone
title="Drag files here or browse"
description="PDF, JPG or PNG up to 10 MB"
acceptedFileTypes={["application/pdf", "image/jpeg", "image/png"]}
isInvalid
errorMessage="Only PDF, JPG and PNG are allowed"
/>
<Dropzone
title="Drag files here or browse"
description="PDF, JPG or PNG up to 10 MB"
acceptedFileTypes={["application/pdf", "image/jpeg", "image/png"]}
isDisabled
/>
<Dropzone
title="Drag files here or browse"
description="PDF, JPG or PNG up to 10 MB"
acceptedFileTypes={["application/pdf", "image/jpeg", "image/png"]}
layout="compact"
isInvalid
errorMessage="Only PDF, JPG and PNG are allowed"
/>
</div>
);
}
With file list
A realistic composition: accepted files are listed as FileItems (here they "upload" at once), a rejected type turns the zone to the Error state with an announced message.
import { useState } from "react";
import { Dropzone, FileItem } from "@nexera-ui/react";
import { LuFileText, LuImage } from "react-icons/lu";
export function WithFileList() {
const [files, setFiles] = useState<File[]>([]);
const [rejected, setRejected] = useState<string | null>(null);
return (
<div className="flex flex-col gap-4">
<Dropzone
title="Drag files here or browse"
description="PDF, JPG or PNG up to 10 MB"
acceptedFileTypes={["application/pdf", "image/jpeg", "image/png"]}
isInvalid={rejected !== null}
errorMessage={rejected === null ? undefined : `${rejected} is not a PDF, JPG or PNG file`}
onSelect={(selected) => {
setRejected(null);
setFiles((current) => [...current, ...selected]);
}}
onReject={(list) => {
setRejected(list.map((file) => file.name).join(", "));
}}
/>
{files.length > 0 ? (
<ul className="m-0 flex list-none flex-col gap-3 p-0">
{files.map((file, index) => (
<li key={`${file.name}${String(index)}`}>
<FileItem
name={file.name}
icon={file.type.startsWith("image/") ? <LuImage /> : <LuFileText />}
status="complete"
meta={`${String(Math.max(1, Math.round(file.size / 1024)))} KB · uploaded`}
onRemove={() => {
setFiles((current) => current.filter((_, i) => i !== index));
}}
/>
</li>
))}
</ul>
) : null}
</div>
);
}
Long text and right to left
Long titles and helpers wrap; right-to-left layouts mirror the compact row.
import { Dropzone } from "@nexera-ui/react";
export function LongTextAndRightToLeft() {
return (
<div className="flex flex-col gap-6">
<Dropzone
acceptedFileTypes={["application/pdf", "image/jpeg", "image/png"]}
title="Drag your signed employment contract and identity documents here, or browse"
description="PDF, JPG or PNG, up to 10 MB each. Scans must show all four corners of the document."
/>
<div dir="rtl" lang="ar">
<Dropzone
layout="compact"
title="اسحب الملفات هنا أو تصفح"
description="PDF أو JPG أو PNG حتى 10 ميغابايت"
browseLabel="تصفح الملفات"
dropTitle="أفلت للرفع"
/>
</div>
</div>
);
}
Props 17
Press "Try it" on a card to load that prop into the playground.
17 props shown
title*NexeraReactNodeVisible title, for example "Drag files here or browse". It names the drop target. The Figma sample is example content.
descriptionNexeraReactNodeHelper text, saying which files are accepted before an error happens ("PDF, JPG or PNG up to 10 MB"). It is read with the drop target and the Browse button.
errorMessageNexeraReactNodeError text that replaces the helper while isInvalid, with the
alert icon in the tile. Announced politely; say what is wrong and how to fix it (WCAG 3.3.1, 3.3.3, 4.1.3).
isInvalidNexerabooleanError state: danger stroke, alert icon and errorMessage. Set it from your own checks (type, size,
count), for example in onReject.
layoutNexera"default" | "compact"Arrangement: a centred column, or a single row for tight spaces.
acceptedFileTypesNexerareadonly string[]Accepted file types as MIME types, wildcards or extensions (["application/pdf", "image/*", ".png"]). Filters the file picker
and sorts dropped or pasted files into onSelect and onReject. Say the same in description.
allowsMultipleNexerabooleanAllow several files at once (picker, drop and paste). With false, only the first accepted file is selected; the rest go to
onReject.
onSelectNexera(files: File[]) => voidCalled with the accepted files from the Browse picker, a drop or a paste. Upload them yourself.
onRejectNexera(files: File[]) => voidCalled with the files that did not match acceptedFileTypes (or extra files when allowsMultiple is false).
browseLabelNexerastringText of the Browse button: the non-drag way to pick files (WCAG 2.5.7). Translate it.
dropTitleNexerastringTitle while files are dragged over the zone, also announced politely. Translate it.
classNameNexerastringExtra classes for the root, merged last so they win over the defaults.
styleNexeraCSSPropertiesInline style of the root.
isDisabledReact AriabooleanWhether the drop target is disabled. If true, the drop target will not accept any drops.
aria-labelReact AriastringDefines a string value that labels the current element.
aria-labelledbyReact AriastringIdentifies the element (or elements) that labels the current element.
aria-describedbyReact AriastringIdentifies the element (or elements) that describes the object.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
10 direct · 2 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.4.1Use of ColorLevel A · tested directly
- 1.4.10ReflowLevel AA · supporting test
- 1.4.12Text SpacingLevel AA · supporting test
- 2.1.1KeyboardLevel A · tested directly
- 2.4.7Focus VisibleLevel AA · tested directly
- 2.5.7Dragging MovementsLevel AA · tested directly
- 3.3.1Error IdentificationLevel A · tested directly
- 3.3.7Redundant EntryLevel A · tested directly
- 4.1.2Name, Role, ValueLevel A · tested directly
- 4.1.3Status MessagesLevel AA · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
data-disableddata-drop-targetdata-hovereddata-invalid
<Dropzone className="data-disabled:opacity-90 shadow-sm" />Used in blocks
Related components
- CalendarDayOne day of a {@link CalendarMonth } grid, built on React Aria `CalendarCell`: a `gridcell` whose button is named by the full, localised date ("Wednesday, October 14, 2026"), with `aria-selected`, `aria-disabled` and the "today" and range descriptions read by screen readers (WCAG 1.3.1, 4.1.2).
- CalendarMonthA month calendar for picking a date or a date range: header with previous / next buttons and the localised month name, weekday row, and six weeks of `CalendarDay`s.
- CheckboxThe bare 18 px checkbox: one independent yes/no choice applied on submit, or a row selector in a table, list or tree.
- CheckboxCardA large checkbox option with an icon, a title and a description, for a few options that need explanation (notification channels, benefits).
- CheckboxFieldA checkbox with a label and optional helper text: the box (the same element as `Checkbox`) followed by the label and description, applied on submit.
- ColorInputA hex colour field with a swatch and a picker popover.
- ColorPickerPicks a colour.
- ColorTokenCardDocumentation card for one colour token: a 96 px colour sample with an "Aa" text sample, then the name, token path, hex value and contrast note as text.