CSS-Only

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 via for attribute
  • Focus-visible indicators on keyboard navigation
  • Disabled state prevents interaction and reduces opacity
  • Respects prefers-reduced-motion for 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 accept attribute and visible text
  • Show file size limits in the label if applicable
  • Provide feedback after file selection (via JavaScript)
  • Use descriptive id attributes that match label for attributes

Complete Examples

Form with File Upload

PDF, DOC, or DOCX only

Image Upload with Preview Zone

Components Used

Other OmniUI components demonstrated on this page: