File Upload
File upload component with native input and drag-and-drop zone. Works purely with CSS, enhances with optional JavaScript for drag events.
Example
<div class="omni-file-input">
<input type="file" multiple>
</div>
Variants
Native File Input
Standard file input with styled file selector button:
<div class="omni-file-input">
<input type="file">
</div>
Multiple Files
Allow selecting multiple files with the multiple attribute:
<div class="omni-file-input">
<input type="file" multiple>
</div>
File Type Restrictions
Use the accept attribute to limit file types:
<!-- Images only -->
<div class="omni-file-input">
<input type="file" accept="image/*">
</div>
<!-- PDFs only -->
<div class="omni-file-input">
<input type="file" accept=".pdf">
</div>
<!-- Multiple types -->
<div class="omni-file-input">
<input type="file" accept=".jpg,.png,.pdf">
</div>
Drag and Drop Zone
Visual drop zone for dragging files. Add data-dragover="true" via JavaScript for drag feedback:
<div class="omni-file-drop">
<div class="omni-file-drop-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M7 18a4.6 4.4 0 0 1 0 -9a5 4.5 0 0 1 11 2h1a3.5 3.5 0 0 1 0 7h-1"/>
<polyline points="9 15 12 12 15 15"/>
<line x1="12" y1="12" x2="12" y2="21"/>
</svg>
</div>
<label class="omni-file-drop-label" for="file-input">
<strong>Click to upload</strong> or drag and drop
</label>
<input type="file" id="file-input" multiple>
</div>
Compact Size
Use data-size="compact" for inline file inputs:
<div class="omni-file-input" data-size="compact">
<input type="file">
</div>
Disabled State
<div class="omni-file-input">
<input type="file" disabled>
</div>
<div class="omni-file-drop">
<label class="omni-file-drop-label" for="file-input">Upload disabled</label>
<input type="file" id="file-input" disabled>
</div>
JavaScript Enhancement
Add drag and drop functionality with minimal JavaScript. The CSS styling works without JS, but JavaScript enhances the experience:
const dropZone = document.querySelector('.omni-file-drop');
const fileInput = dropZone.querySelector('input[type="file"]');
// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, (e) => {
e.preventDefault();
e.stopPropagation();
});
});
// Visual feedback on drag
dropZone.addEventListener('dragenter', () => {
dropZone.setAttribute('data-dragover', 'true');
});
dropZone.addEventListener('dragleave', (e) => {
if (e.target === dropZone) {
dropZone.removeAttribute('data-dragover');
}
});
// Handle drop
dropZone.addEventListener('drop', (e) => {
dropZone.removeAttribute('data-dragover');
const files = e.dataTransfer.files;
fileInput.files = files;
// Trigger change event
fileInput.dispatchEvent(new Event('change', { bubbles: true }));
});
// Handle file selection
fileInput.addEventListener('change', (e) => {
const files = e.target.files;
console.log('Files selected:', files);
// Handle file upload logic
});
API Reference
CSS Classes
| Class | Description |
|---|---|
.omni-file-input |
Wrapper for native file input with styled button |
.omni-file-drop |
Drag and drop zone container |
.omni-file-drop-label |
Label text inside drop zone |
.omni-file-drop-icon |
Icon container (optional) |
Data Attributes
| Attribute | Values | Default | Description |
|---|---|---|---|
data-size |
compact | — | Makes file input inline (on .omni-file-input) |
data-dragover |
true | — | Visual feedback during drag (on .omni-file-drop) |
Native Input Attributes
| Attribute | Example | Description |
|---|---|---|
multiple |
multiple |
Allow selecting multiple files |
accept |
image/*, .pdf |
Restrict file types |
disabled |
disabled |
Disable file selection |
required |
required |
Make file selection required |
Accessibility
- Uses native
<input type="file">for full keyboard support - Drop zone has proper
<label>associated with input viaforattribute - Focus-visible indicators on keyboard navigation
- Disabled state prevents interaction and reduces opacity
- Respects
prefers-reduced-motionfor drag animations - High contrast mode support with increased border width
- Screen readers announce file input and label text
- Works with keyboard-only navigation (Tab, Enter, Space)
Best Practices
- Always include clear instructions in the label
- Specify accepted file types in both
acceptattribute and visible text - Show file size limits in the label if applicable
- Provide feedback after file selection (via JavaScript)
- Use descriptive
idattributes that match labelforattributes
Complete Examples
Form with File Upload
Image Upload with Preview Zone
Components Used
Other OmniUI components demonstrated on this page: