Lightweight Custom File Input Control – FileBokz

Category: Form | April 18, 2025
Author:fivefifteen
Views Total:0 views
Official Page:Go to website
Last Update:April 18, 2025
License:MIT

Preview:

Lightweight Custom File Input Control – FileBokz

Description:

FileBokz is a tiny yet powerful JavaScript library for enhancing standard HTML file inputs.

It transforms the native file input into a highly customizable, feature-rich UI component with drag-and-drop capabilities, file previews, and robust validation options.

Features:

  • Tiny Footprint: Around 10kb total (JS+CSS), minimal impact on load times. Add ~4kb for the optional theme.
  • Zero Dependencies: No external libraries needed. It just works.
  • Flexible Markup: Use as much or as little HTML structure as you need inside the main container.
  • Optional CSS Theme: Comes with decent default styling, but you can easily override or replace it.
  • Drag-and-Drop: Supports dragging files onto the element, dragging files out to remove them, and even dragging between multiple FileBokz instances.
  • Append/Remove Files: Allows adding more files without replacing existing ones (configurable) and removing individual files.
  • Image Previews: Generates temporary URLs for image previews right in the browser. You can specify fallback content for non-image types.
  • Client-Side Validation: Configure allowed extensions, max files, max individual file size, and max total size with customizable error messages.
  • Highly Configurable: Almost every aspect, from error message timing to file display content, can be adjusted via data attributes.
  • Standard Form Integration: Selected files are managed within the original <input type="file">, submitting naturally with your form.

How to use it:

1. Install and import FileBokz via NPM.

# NPM
$ npm install filebokz
// ES6
import filebokz from 'filebokz'
// CommonJS
const filebokz = require('filebokz')

2. Or download the package and load the following files in your document.

<!-- Core Stylesheet -->
<link rel="stylesheet" href="dist/filebokz.min.css" />
<!-- Optional Theme -->
<link rel="stylesheet" href="dist/filebokz-theme.min.css" />
<!-- Core JavaScript -->
<script type="text/javascript" src="dist/filebokz.min.js"></script>

3. Add a regular HTML file input into the FileBokz container as follows:

<div class="filebokz">
  <input type="file" id="file-1" name="file" />
  <label for="file-1">
    <strong class="no-files">Choose a file</strong>
    <span class="no-files is-draggable">or drag it here</span>
    <span class="files"></span>
    <span class="error-msg"></span>
  </label>
</div>

4. Call the filebokz() function after the DOM is ready.

window.addEventListener('load', function () {
  // Initialize all elements with the default class 'filebokz'
  filebokz();
  // Initialize elements with a custom class, don't add 'filebokz' class
  // filebokz('.custom-file-input', false);
  // Initialize a specific element by ID
  // filebokz(document.getElementById('my-unique-input'));
});

5. Apply these attributes to your main FileBokz container element:

  • data-allowed-extensions: Comma-separated list of allowed file extensions (e.g., jpg,png,pdf). Use [none] for files without extensions. Defaults to allowing all.
  • data-allowed-extensions-error-msg: Custom error message for disallowed file types. {variable} is replaced with the allowed list. (Default: Only the following file types are allowed: {variable}.)
  • data-appendable: Set to false to replace files on new selection instead of adding. (Default: true)
  • data-auto-submit: Set to true to submit the parent form automatically upon file selection/change. (Default: false)
  • data-error-display-animation-duration: Milliseconds after error-display-duration before clearing the error message content. (Default: 250)
  • data-error-display-duration: Milliseconds to keep the error class on the root element after an error. (Default: 3000)
  • data-max-files: Maximum number of files allowed (only if input has multiple). (Default: null, no limit)
  • data-max-files-error-msg: Custom error message for exceeding max files. {variable} is the max number, {s} becomes “s” if > 1. (Default: A maximum of {variable} file{s} can be uploaded.)
  • data-max-file-size: Maximum size (in KB) for a single file. (Default: null, no limit)
  • data-max-file-size-error-msg: Custom error message for exceeding single file size limit. {variable} is the max size. (Default: File size cannot exceed {variable}.)
  • data-max-size: Maximum combined size (in KB) for all files. (Default: null, no limit)
  • data-max-size-error-msg: Custom error message for exceeding total size limit. {variable} is the max total size. (Default: Total combined file size cannot exceed {variable}.)
<div class="filebokz"
     data-allowed-extensions="jpg,png"
     data-allowed-extensions-error-msg="Please upload only JPG or PNG images."
     data-max-files="5"
     data-max-files-error-msg="You can upload a maximum of {variable} images."
     data-max-file-size="2048"
     data-max-file-size-error-msg="Single image size cannot exceed {variable}KB."
     data-max-size="10240"
     data-max-size-error-msg="Total size of all images cannot exceed {variable}KB."
     data-appendable="true">
     ...
</div>

6. Apply these attributes to the element inside your main FileBokz container that has the files class (e.g., <span class="files" data-attribute="value">). These control the rendering of each individual file item that gets added.

  • data-content: Defines the main HTML content for each file item. Placeholders {name}, {size}, {type}, {url} are replaced. (Default: {name})
  • data-content-before: HTML content prepended to the data-content. Uses the same placeholders. (Default: null)
  • data-content-after: HTML content appended to the data-content. Uses the same placeholders. (Default: null)
  • data-draggable: Set to false to prevent individual file items from being draggable (for removal or moving between instances). (Default: true)
  • data-element: Specifies the HTML tag name for each generated file item element. (Default: span)
  • data-url: Provides a default URL for the {url} placeholder, used especially when the file is not an image (for images, {url} defaults to a temporary preview URL). (Default: null)
<div class="filebokz" data-max-files="3">
  <input type="file" name="attachments" id="attachments-input" multiple />
  <label for="attachments-input">
    <strong class="no-files">Add Attachments</strong>
    <span class="no-files is-draggable"> or drag them here</span>
    <!-- This div has the 'files' class and the customization attributes -->
    <div class="files file-previews"
         data-element="div"
         data-url="/icons/default-file-icon.svg"
         data-content-before="<img src='{url}' alt='Preview' class='file-preview-thumb'> "
         data-content="{name} ({size})"
         data-content-after=" <button type='button' class='remove file-remove-btn'>Remove</button>">
      <!-- File items will be appended here by FileBokz -->
    </div>
    <span class="error-msg"></span>
    <div class="has-files">
      Files: <span class="file-count">0</span>/3 | Size: <span class="size">0 KB</span>
    </div>
  </label>
</div>

7. Customize the enhanced file input with the following CSS classes:

  • State Indicators (Visibility controlled by root classes):
    • error: Shown only when the root element has the error class (e.g., validation failed).
    • has-files: Shown only when the root element has the has-files class (input contains one or more files).
    • in-focus: Shown only when the root element has the in-focus class.
    • is-advanced: Shown only when the root element has is-advanced (browser supports advanced features).
    • is-draggable: Shown only when the root element has is-draggable (browser supports drag & drop).
    • is-dragging: Shown only when the root element has is-dragging (a file is being dragged over this element).
    • is-removing: Shown only when the root element has is-removing (a file is being dragged out of this element for removal).
    • is-transferring: Shown only when the root element has is-transferring (a file is being dragged out to another FileBokz element).
    • js-enabled: Shown only after FileBokz JavaScript has successfully initialized for this element.
    • no-files: Shown only when the root element lacks the has-files class (input is empty).
    • not-in-focus: Shown only when the root element lacks the in-focus class.
    • not-advanced: Shown only when the root element lacks the is-advanced class.
    • not-draggable: Shown only when the root element lacks the is-draggable class.
    • not-dragging: Shown only when the root element lacks the is-dragging class.
    • not-removing: Shown only when the root element lacks the is-removing class.
    • not-transferring: Shown only when the root element lacks the is-transferring class.
  • Content Injection/Update:
    • error-msg: Its inner HTML is replaced with the current error message text.
    • file-count: Its inner HTML is replaced with the number of files currently selected.
    • size: Its inner HTML is replaced with the total combined size of all selected files (human-readable format).
  • Structure & Interaction:
    • files: An element with this class acts as the container where FileBokz will append the individual file items (each typically having the file class).
    • file: This class is automatically applied by FileBokz to each element it generates to represent an individual file within the files container. (You don’t usually add this manually in the initial HTML).
    • file-previews: Add this class alongside files for potentially enhanced default styling when using the optional filebokz-theme.css and displaying image previews.
    • remove: Add this class to an element within the file item template (defined via data-content* attributes on the files element). Clicking an element with this class will remove the corresponding file.
<form>
  <div class="filebokz" data-max-files="5" data-max-size="10240">
    <!-- Hidden actual file input -->
    <input type="file" name="documents" id="doc-input" multiple />
    <!-- Label acts as the main UI area -->
    <label for="doc-input" class="filebokz-label">
      <!-- Initial state message (shown when no files) -->
      <div class="no-files">
        <strong>Choose files</strong>
        <span class="is-draggable"> or drag them here.</span>
        <span class="not-draggable"> (Drag & Drop not supported)</span>
        <small>Max 5 files, 10MB total.</small>
      </div>
      <!-- State shown when dragging over -->
      <div class="is-dragging">
        <strong>Drop files now!</strong>
      </div>
      <!-- State shown when files are present -->
      <div class="has-files">
        <p>Selected Files (<span class="file-count">0</span>/5):</p>
        <!-- Container for file list items -->
        <div class="files file-previews"
             data-element="div"
             data-content="{name} ({size})"
             data-content-after=" <button type='button' class='remove' title='Remove file'>&times;</button>">
          <!-- FileBokz adds file items here -->
        </div>
        <p>Total size: <span class="size">0 KB</span></p>
      </div>
      <!-- Error message area -->
      <div class="error">
        <strong class="error-msg" style="color: red;"></strong>
      </div>
      <!-- Focus indicator example -->
      <div class="focus-indicator">
          <span class="in-focus">Input is focused</span>
          <span class="not-in-focus">Input is not focused</span>
      </div>
      <!-- JS detection example -->
      <div class="js-status">
          <span class="js-enabled">JavaScript Enhanced</span>
          <!-- You might have fallback content visible by default that you hide via CSS if .js-enabled is present -->
      </div>
    </label>
  </div>
  <button type="submit">Submit Form</button>
</form>

8. Event handlers.

fileInputContainer.addEventListener('file-added', function (e) {
  console.log('File added:', e.detail.file); // Access the added File object
  // Update other parts of the UI
});
fileInputContainer.addEventListener('file-removed', function (e) {
  console.log('File removed:', e.detail.file); // Access the removed File object
});
fileInputContainer.addEventListener('error', function (e) {
  console.error('FileBokz Error:', e.detail.errorType, e.detail.errorMessage);
  // Display a custom notification
});

You Might Be Interested In:


Leave a Reply