File Upload Flow
A server-ready multipart upload workflow with validation and request states.
Preview
@props([
'action' => '#',
'method' => 'POST',
'title' => 'Upload files',
'description' => 'Add files for review and processing.',
'fieldName' => 'documents',
'accept' => '.pdf,.png,.jpg,.jpeg',
'maxSize' => 10,
'multiple' => true,
'statusMessage' => null,
'failureMessage' => null,
'cancelHref' => null,
'submitLabel' => 'Upload files',
])
<x-ui.form.guard
as="section"
data-slot="file-upload-flow"
data-surface="admin"
{{ $attributes->merge(['class' => 'bg-background text-foreground']) }}
>
<div class="mx-auto max-w-2xl">
<div class="mb-4 space-y-4" aria-live="polite" aria-atomic="true">
@if ($statusMessage)
<x-ui.alert variant="success" role="status">{{ __($statusMessage) }}</x-ui.alert>
@endif
@if ($failureMessage)
<x-ui.alert variant="destructive">{{ __($failureMessage) }}</x-ui.alert>
@endif
</div>
<x-ui.form
:action="$action"
:method="$method"
:has-files="true"
:summary="__('Please correct the upload errors below.')"
data-persisted-form
>
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __($title) }}</x-ui.card.title>
<x-ui.card.description>{{ __($description) }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.field :name="$fieldName" :label="__('Files')" :hint="__('The server checks file type, size, count, and access again after upload.')" required>
<x-ui.dropzone :accept="$accept" :max-size="$maxSize" :multiple="$multiple" />
</x-ui.field>
</x-ui.card.content>
<x-ui.card.footer class="flex flex-col-reverse gap-2 border-t border-border sm:flex-row sm:justify-end">
@if ($cancelHref)
<x-ui.button :href="$cancelHref" variant="ghost">{{ __('Cancel') }}</x-ui.button>
@endif
<x-ui.button type="submit" x-bind:disabled="submitting" x-bind:aria-busy="submitting">
<span x-show="! submitting">{{ __($submitLabel) }}</span>
<span x-cloak x-show="submitting">{{ __('Uploading…') }}</span>
</x-ui.button>
</x-ui.card.footer>
</x-ui.card>
</x-ui.form>
</div>
</x-ui.form.guard>
Installation
php artisan ui:add blocks/file-upload-flow-multipart
Registry contract
Install confidence
php artisan ui:add blocks/file-upload-flow-multipart
writes only the generated targets below. The CLI validates each file hash before writing and
prompts before replacing local changes unless --force is used.
- Version
- 1.1.4
- License
- open
- Stability
- stable
- Contract
- v2
- Foundation
- ≥ 1.0.0
| Type | Generated target |
|---|---|
| blade | resources/views/blocks/file-upload-flow-multipart.blade.php |
Registry dependencies
Package dependencies
composer: jml/brok:^0.2
npm: alpinejs
Use with AI
A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.
# Brok UI block: File Upload Flow (`file-upload-flow-multipart`)
A server-ready multipart upload flow with Dropzone selection, validation feedback, progress state, unsaved-file protection, and success or failure feedback.
Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.
## Install
```bash
php artisan ui:add blocks/file-upload-flow-multipart
```
## Render it
```blade
<x-blocks.file-upload-flow-multipart />
```
## Props
- `action` (string, default `#`) — Multipart upload endpoint.
- `method` (string, default `POST`) — Upload request method.
- `title` (string, default `Upload files`) — Upload card heading.
- `description` (string, default `Add files for review and processing.`) — Upload card description.
- `field-name` (string, default `documents`) — Laravel validation and upload field key.
- `accept` (string|null, default `.pdf,.png,.jpg,.jpeg`) — Client file-picker hint.
- `max-size` (int, default `10`) — Client maximum size in MB per file.
- `multiple` (bool, default `true`) — Allows multiple selected files.
- `status-message` (string|null, default `null`) — Success feedback after redirect.
- `failure-message` (string|null, default `null`) — Safe upload failure feedback.
- `cancel-href` (string|null, default `null`) — Optional cancel destination.
- `submit-label` (string, default `Upload files`) — Upload action label.
## Use when
- Use for one or more files that are submitted to a Laravel endpoint as one form request.
## Avoid when
- Use a resumable direct-upload client for very large files or unreliable network connections.
- Uploading a single file with a simple drop target; use the dropzone primitive alone instead.
## Rules
- Render the installed block with `<x-blocks.file-upload-flow-multipart />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.
## Links
- Docs: https://brokui.dev/blocks/file-upload-flow-multipart
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/file-upload-flow-multipart.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
Guidance
Use when
- Use for one or more files that are submitted to a Laravel endpoint as one form request.
Avoid when
- Use a resumable direct-upload client for very large files or unreliable network connections.
- Uploading a single file with a simple drop target; use the dropzone primitive alone instead.
Anti-patterns
- Do not replace semantic props with conflicting utility classes.
- Do not remove labels, focus styles, or state attributes.
- Anatomy
- Theming hooks
Usage
Render the block as a component, passing data where useful:
<x-blocks.file-upload-flow-multipart />
Built from primitives
This block composes installed <brok:*> primitives and semantic design
tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by
editing CSS variables; flip the preview to RTL to confirm it mirrors.
Source
The exact, editable file ui:add writes
into your app. The preview above renders this same source — there are no preview-only blocks.
@props([
'action' => '#',
'method' => 'POST',
'title' => 'Upload files',
'description' => 'Add files for review and processing.',
'fieldName' => 'documents',
'accept' => '.pdf,.png,.jpg,.jpeg',
'maxSize' => 10,
'multiple' => true,
'statusMessage' => null,
'failureMessage' => null,
'cancelHref' => null,
'submitLabel' => 'Upload files',
])
<x-ui.form.guard
as="section"
data-slot="file-upload-flow"
data-surface="admin"
{{ $attributes->merge(['class' => 'bg-background text-foreground']) }}
>
<div class="mx-auto max-w-2xl">
<div class="mb-4 space-y-4" aria-live="polite" aria-atomic="true">
@if ($statusMessage)
<x-ui.alert variant="success" role="status">{{ __($statusMessage) }}</x-ui.alert>
@endif
@if ($failureMessage)
<x-ui.alert variant="destructive">{{ __($failureMessage) }}</x-ui.alert>
@endif
</div>
<x-ui.form
:action="$action"
:method="$method"
:has-files="true"
:summary="__('Please correct the upload errors below.')"
data-persisted-form
>
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __($title) }}</x-ui.card.title>
<x-ui.card.description>{{ __($description) }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.field :name="$fieldName" :label="__('Files')" :hint="__('The server checks file type, size, count, and access again after upload.')" required>
<x-ui.dropzone :accept="$accept" :max-size="$maxSize" :multiple="$multiple" />
</x-ui.field>
</x-ui.card.content>
<x-ui.card.footer class="flex flex-col-reverse gap-2 border-t border-border sm:flex-row sm:justify-end">
@if ($cancelHref)
<x-ui.button :href="$cancelHref" variant="ghost">{{ __('Cancel') }}</x-ui.button>
@endif
<x-ui.button type="submit" x-bind:disabled="submitting" x-bind:aria-busy="submitting">
<span x-show="! submitting">{{ __($submitLabel) }}</span>
<span x-cloak x-show="submitting">{{ __('Uploading…') }}</span>
</x-ui.button>
</x-ui.card.footer>
</x-ui.card>
</x-ui.form>
</div>
</x-ui.form.guard>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.1.4 - Status
- Stable
- License
-
open - Deprecation
- Not deprecated
- Contract
-
v2 - Foundation
-
≥ 1.0.0