Upload
File upload component with optional drag & drop dropzone, preview, and validation.
Key Features
- Two Modes - Default styled input or drag & drop dropzone
- File Type Filtering - Accept specific file types with symbols (:image, :pdf, :document)
- Size Limits - Set max file size per file
- File Count Limits - Limit number of files for multiple uploads
- Live Preview - Image thumbnails and file lists with remove buttons
- Client Validation - Type, size, and count validated before upload
- Form Builder - Full Rails form integration (
f.rui_upload) - 5 Sizes - xs, sm, base, lg, xl
- 3 Variants - Default, filled, outline
- Full Accessibility - ARIA attributes, keyboard navigation
- JavaScript API - Programmatic control with
data-actionattributes
Basic Usage
Simple file upload with label and help text using the styled native file input.
Upload your CV in PDF format
<%= rui_upload(name: :avatar, label: "Profile Picture") %>
<%= rui_upload(
name: :resume,
label: "Resume",
help_text: "Upload your CV in PDF format"
) %>
Dropzone Mode
Enable drag & drop with the dropzone: true option. Users can drag files onto the area or click to browse.
Drop file here or click to upload
Max size: 10.0 MB
<%= rui_upload(
name: :document,
label: "Upload Document",
dropzone: true
) %>
Tip: The dropzone area highlights when files are dragged over it. The border becomes dashed and the background changes to indicate the active drop state.
Multiple Files
Allow users to select multiple files with the multiple: true option.
Default Mode - Multiple Files
Select multiple photos to upload
Dropzone Mode - Multiple Files
Drop files here or click to upload
Max size: 10.0 MB • Max files: 10
Drop multiple files here
<%# Default mode with multiple files %>
<%= rui_upload(
name: :photos,
label: "Photo Gallery",
multiple: true
) %>
<%# Dropzone mode with multiple files %>
<%= rui_upload(
name: :attachments,
label: "Attachments",
dropzone: true,
multiple: true
) %>
Note: When multiple: true is set, the input name automatically gets [] appended (e.g., photos[]) for proper array handling in Rails.
File Restrictions
Control allowed file types, maximum file size, and maximum number of files.
Accept File Types
Use symbols for common file type presets, or provide a custom MIME type string.
Accepts PNG, JPEG, GIF, WebP, SVG
Accepts PDF, Word documents
Custom MIME type string
<%# Symbol presets %>
<%= rui_upload(name: :photos, accept: [:image], label: "Images") %>
<%= rui_upload(name: :docs, accept: [:pdf, :document], label: "Documents") %>
<%= rui_upload(name: :data, accept: [:spreadsheet], label: "Spreadsheets") %>
<%= rui_upload(name: :audio, accept: [:audio], label: "Audio Files") %>
<%= rui_upload(name: :video, accept: [:video], label: "Video Files") %>
<%# Custom MIME types %>
<%= rui_upload(name: :file, accept: "image/png,.pdf", label: "Custom") %>
Available Presets
| Symbol | MIME Types |
|---|---|
| :image | PNG, JPEG, GIF, WebP, SVG |
| application/pdf | |
| :document | Word (.doc, .docx), OpenDocument |
| :spreadsheet | Excel (.xls, .xlsx), CSV, OpenDocument |
| :audio | MP3, WAV, OGG, AAC, WebM Audio |
| :video | MP4, WebM, OGG Video, MOV |
| :archive | ZIP, RAR, TAR, GZIP, 7Z |
Size and Count Limits
Limit file size and number of files. Validation happens client-side before upload.
Files larger than 2MB will be rejected
Drop files here or click to upload
Max size: 10.0 MB • Max files: 3
Upload up to 3 files
Drop files here or click to upload
Accepted: Image • Max size: 5.0 MB • Max files: 5
<%# Max file size %>
<%= rui_upload(
name: :avatar,
max_file_size: 2.megabytes,
label: "Avatar (max 2MB)"
) %>
<%# Max file count %>
<%= rui_upload(
name: :photos,
multiple: true,
max_files: 5,
label: "Photos (max 5)"
) %>
<%# Combined restrictions %>
<%= rui_upload(
name: :gallery,
dropzone: true,
multiple: true,
accept: [:image],
max_file_size: 5.megabytes,
max_files: 10,
label: "Gallery"
) %>
Variants
Three visual variants for different design contexts.
Default
Filled
Outline
<%= rui_upload(name: :file, variant: :default, label: "Default") %>
<%= rui_upload(name: :file, variant: :filled, label: "Filled") %>
<%= rui_upload(name: :file, variant: :outline, label: "Outline") %>
Sizes
Five size options from extra small to extra large.
<%= rui_upload(name: :file, size: :xs, label: "Extra Small") %>
<%= rui_upload(name: :file, size: :sm, label: "Small") %>
<%= rui_upload(name: :file, size: :base, label: "Base (default)") %>
<%= rui_upload(name: :file, size: :lg, label: "Large") %>
<%= rui_upload(name: :file, size: :xl, label: "Extra Large") %>
States
Required, disabled, and error states.
File type not accepted
<%= rui_upload(name: :file, required: true, label: "Required") %>
<%= rui_upload(name: :file, disabled: true, label: "Disabled") %>
<%= rui_upload(name: :file, error: "File type not accepted", label: "With Error") %>
Form Builder Integration
Use with Rails form builder for automatic object binding.
<%= form_with model: @user do |f| %>
<%# Single file upload %>
<%= f.rui_upload(:avatar,
label: "Profile Picture",
accept: [:image],
max_file_size: 2.megabytes
) %>
<%# Multiple files with dropzone %>
<%= f.rui_upload(:documents,
label: "Documents",
dropzone: true,
multiple: true,
accept: [:pdf, :document],
max_files: 10
) %>
<%= f.rui_button("Upload") %>
<% end %>
Note: When using f.rui_upload, the component automatically generates the correct name (e.g., user[avatar]) and handles multiple file arrays.
ActiveStorage Integration
The upload component is storage-agnostic - it renders a standard file input that works with ActiveStorage, Shrine, CarrierWave, or any file handling approach.
<%# Model with has_one_attached %>
class User < ApplicationRecord
has_one_attached :avatar
has_many_attached :documents
end
<%# Form %>
<%= form_with model: @user do |f| %>
<%= f.rui_upload(:avatar,
label: "Avatar",
accept: [:image]
) %>
<%= f.rui_upload(:documents,
label: "Documents",
multiple: true
) %>
<% end %>
Real-World Example: Post Form
See the upload component in action on the New Post and Posts pages.
Accessibility
The Upload component follows WAI-ARIA best practices for file upload controls.
ARIA Attributes
-
Help text and errors linked via
aria-describedby -
Required fields include
aria-required="true" -
Error messages displayed with
role="alert"
Keyboard Navigation
- Tab focuses the upload area
- Enter or Space opens the file picker
- Focus states are clearly visible with ring styles
- Remove buttons on file items are keyboard accessible
Semantic HTML
-
Uses native
<input type="file">element -
Labels use
forattribute linked to inputid - Dropzone uses proper ARIA roles for drag-and-drop
Screen Reader Support
- File selection status is announced
- Validation errors are announced for file type/size issues
- File list is announced with count and names
JavaScript API
The upload uses the upload Stimulus controller for file handling, drag & drop, preview, and validation.
Stimulus Actions
Trigger upload behavior from any element:
| Action | Description |
|---|---|
upload#triggerFileInput |
Open the native file picker dialog |
upload#selectFiles |
Handle files selected via input (called on change event) |
upload#handleDragOver |
Show visual feedback when dragging files over dropzone |
upload#handleDragLeave |
Remove visual feedback when dragging leaves dropzone |
upload#handleDrop |
Process files dropped onto the dropzone |
upload#removeFile |
Remove a file from the preview list |
Drop files here or click to browse
Controller Values
Configure the upload behavior:
| Value | Type | Default | Description |
|---|---|---|---|
multiple |
Boolean | false |
Allow selecting multiple files |
maxFiles |
Number | 10 |
Maximum number of files allowed |
maxFileSize |
Number | 10485760 |
Maximum file size in bytes (10 MB default) |
accept |
String | "" |
Accepted MIME types (comma-separated) |
Programmatic Control
Control the upload directly via Stimulus controller:
// Get the controller instance
const element = document.querySelector('[data-controller="upload"]')
const controller = this.application.getControllerForElementAndIdentifier(element, 'upload')
// Open file picker programmatically
controller.triggerFileInput({ preventDefault: () => {} })
// Access current files
console.log('Selected files:', controller.files)
// Clear all files by resetting
controller.files = []
// Clear preview using DOM methods
while (controller.previewTarget.firstChild) {
controller.previewTarget.removeChild(controller.previewTarget.firstChild)
}
// Check validation settings
console.log('Max file size:', controller.maxFileSizeValue)
console.log('Accepted types:', controller.acceptValue)
Note: The upload controller validates files client-side before adding them to the preview. Files that exceed size limits or don't match accepted types are rejected with an error message displayed in the error target.
API Reference
rui_upload
File upload component with drag-and-drop, preview, and validation
| Parameter | Type | Default | Description |
|---|---|---|---|
| name_or_method* | Symbol/String | — | Positional first arg - name for standalone, method for form builder |
Appearance
Visual styling options
| Parameter | Type | Default | Description |
|---|---|---|---|
| variant | Symbol |
:dropzone
|
Visual style
:dropzone
:button
:minimal
|
| color | Symbol |
:primary
|
Accent color - semantic or any Tailwind color |
| size | Symbol |
:base
|
Component size
:xs
:sm
:base
:lg
:xl
|
| shape | Symbol |
:rounded
|
Border radius
:square
:rounded
:pill
|
File Validation
File type and size validation options
| Parameter | Type | Default | Description |
|---|---|---|---|
| accept | String/Array | — | Accepted file types (e.g., 'image/*', '.pdf', ['image/png', 'image/jpeg']) |
| max_size | Integer/String | — | Maximum file size in bytes or human format ('5MB') |
| min_size | Integer/String | — | Minimum file size |
Preview Options
File preview configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
| preview | Boolean |
true
|
Show file preview after selection |
| preview_size | Symbol |
:base
|
Preview thumbnail size
:xs
:sm
:base
:lg
:xl
|
| remove_button | Boolean |
true
|
Show remove button on preview |
Multiple Files
Multiple file upload options
| Parameter | Type | Default | Description |
|---|---|---|---|
| multiple | Boolean |
false
|
Allow multiple file selection |
| max_files | Integer | — | Maximum number of files (when multiple) |
Labels & Text
Text options
| Parameter | Type | Default | Description |
|---|---|---|---|
| label | String | — | Label text displayed above upload |
| help_text | String | — | Help text displayed below upload |
| dropzone_text | String | — | Custom text inside dropzone |
| button_text | String | — | Custom button text |
States
State options
| Parameter | Type | Default | Description |
|---|---|---|---|
| required | Boolean |
false
|
Show required indicator (*) |
| disabled | Boolean |
false
|
Disable the upload |
Form Builder
Options when used with Rails form builder (f.rui_upload)
| Parameter | Type | Default | Description |
|---|---|---|---|
| form | FormBuilder | — | Rails form builder instance |
| object | Object/Symbol | — | Object to bind upload to |
| direct_upload | Boolean |
false
|
Enable Active Storage direct upload |