File Upload
A drag-and-drop file field built on a real hidden file input, with client-side validation, a rejection channel and a rendered file list.
<NaviusFileUpload Multiple MaxFiles="4" Accept="image/*,.pdf" class="space-y-3">
<NaviusFileUploadDropzone class="rounded-lg border border-dashed p-6 text-center data-[dragging]:border-primary">
<NaviusFileUploadInput />
Drop files here, or <NaviusFileUploadTrigger>browse</NaviusFileUploadTrigger>
</NaviusFileUploadDropzone>
<NaviusFileUploadList>
<ItemTemplate Context="file">
<div class="flex items-center gap-2 rounded-md border px-2 py-1">
<NaviusFileUploadItemName class="flex-1 truncate" />
<NaviusFileUploadItemSize class="text-xs text-muted-foreground" />
<NaviusFileUploadItemDelete aria-label="Remove file">×</NaviusFileUploadItemDelete>
</div>
</ItemTemplate>
</NaviusFileUploadList>
</NaviusFileUpload>Features
- The hidden
<input type="file">(the Input part) is the a11y + form source of truth; the Trigger and Dropzone merely relay to it, so native keyboard, the OS dialog and screen-reader announcements come for free. - A drop anywhere on the root copies files into the input;
data-draggingmirrors the engine's drag state onto the root and dropzone. - Each selection is validated against
Accept/MaxSize/MaxFiles; accepted files raiseOnAccepted, refused ones raiseOnRejectedwith a reason. - Controlled via
@bind-Filesor uncontrolled; a polite live region announces added / rejected / removed counts.
Installation
Install the brain, or copy just this primitive in with the CLI.
navius add file-uploadAnatomy
Import the parts and assemble them. The Input must live inside the Dropzone (or the root); the List renders one Item per file.
@using Navius.Primitives.Components.FileUpload
<NaviusFileUpload>
<NaviusFileUploadDropzone>
<NaviusFileUploadInput />
<NaviusFileUploadTrigger />
</NaviusFileUploadDropzone>
<NaviusFileUploadList>
<ItemTemplate Context="file">
<NaviusFileUploadItemName />
<NaviusFileUploadItemSize />
<NaviusFileUploadItemDelete />
</ItemTemplate>
</NaviusFileUploadList>
<NaviusFileUploadClear />
</NaviusFileUpload>API Reference
Root
NaviusFileUpload. Owns the file list, validation and the drag/drop relay. Renders a div with a visually-hidden polite status region. Files is two-way bindable.
| Prop | Type | Default |
|---|---|---|
| Files | IReadOnlyList<IBrowserFile>? | - |
| FilesChanged | EventCallback<IReadOnlyList<IBrowserFile>> | - |
| Accept | string? | - |
| Multiple | bool | false |
| MaxFiles | int? | - |
| MaxSize | long | 0 |
| Directory | bool | false |
| Capture | string? | - |
| Disabled | bool | false |
| Name | string? | - |
| OnAccepted | EventCallback<IReadOnlyList<IBrowserFile>> | - |
| OnRejected | EventCallback<IReadOnlyList<NaviusFileRejection>> | - |
| ChildContent | RenderFragment? | - |
| …attributes | IDictionary<string, object>? | - |
Data attributes
| Data attribute | Values |
|---|---|
| [data-navius-file-upload] | Present on the root |
| [data-disabled] | Present when disabled |
| [data-invalid] | Present when the last selection had a rejection |
| [data-dragging] | Present while files are dragged over the root |
Dropzone
NaviusFileUploadDropzone. A focusable drop target; Enter/Space open the file dialog. Renders a div with role=button.
| Prop | Type | Default |
|---|---|---|
| AriaLabel | string? | "Drop files here or press Enter to browse" |
| ChildContent | RenderFragment? | - |
| …attributes | IDictionary<string, object>? | - |
Data attributes
| Data attribute | Values |
|---|---|
| [data-navius-file-upload-dropzone] | Present on the drop target |
| [data-dragging] | Present while files are dragged over it |
| [data-disabled] | Present when disabled |
Input
NaviusFileUploadInput. The real, visually-hidden InputFile (a11y + form truth). accept / multiple / webkitdirectory / capture / name flow from the root. Renders an input.
| Prop | Type | Default |
|---|---|---|
| …attributes | IDictionary<string, object>? | - |
Trigger
NaviusFileUploadTrigger. A plain button that opens the OS dialog by relaying to the input. Renders a button.
| Prop | Type | Default |
|---|---|---|
| ChildContent | RenderFragment? | - |
| …attributes | IDictionary<string, object>? | - |
Data attributes
| Data attribute | Values |
|---|---|
| [data-navius-file-upload-trigger] | Present on the trigger button |
| [data-disabled] | Present when disabled |
List
NaviusFileUploadList. The selected-files list; auto-renders one Item per file via ItemTemplate, or takes explicit children. Renders a ul with role=list.
| Prop | Type | Default |
|---|---|---|
| ItemTemplate | RenderFragment<IBrowserFile>? | - |
| ChildContent | RenderFragment? | - |
| …attributes | IDictionary<string, object>? | - |
Item
NaviusFileUploadItem. One file row; cascades a context so its name/size/delete children know their file. Renders an li with role=listitem.
| Prop | Type | Default |
|---|---|---|
| File | IBrowserFile | required |
| Invalid | bool | false |
| ChildContent | RenderFragment? | - |
| …attributes | IDictionary<string, object>? | - |
Data attributes
| Data attribute | Values |
|---|---|
| [data-navius-file-upload-item] | Present on each row |
| [data-invalid] | Present when the row is marked invalid |
ItemName / ItemSize / ItemDelete
Inside an Item: the file name (span), the human-readable size (span) and a per-file remove button (button, aria-label 'Remove {name}'). Each takes an optional child + splat.
| Prop | Type | Default |
|---|---|---|
| ChildContent | RenderFragment? | - |
| …attributes | IDictionary<string, object>? | - |
Clear
NaviusFileUploadClear. Clears all files; disabled when the list is already empty. Renders a button.
| Prop | Type | Default |
|---|---|---|
| ChildContent | RenderFragment? | - |
| …attributes | IDictionary<string, object>? | - |
Data attributes
| Data attribute | Values |
|---|---|
| [data-navius-file-upload-clear] | Present on the clear button |
| [data-disabled] | Present when disabled or the list is empty |
Accessibility
The interactive path is a real file input, so keyboard and the OS dialog work natively. The Dropzone follows react-aria's DropZone (role="button", Enter / Space to browse); drag-and-drop is pointer-only sugar. A visually-hidden role="status" aria-live="polite" region announces added / rejected / removed counts. Rejections arrive as NaviusFileRejection with a FileRejectionReason (TooLarge / TooMany / WrongType).