Media Image Upload

Image Upload

A single-image upload control with a live preview. Wrap a native <input type="file"> in .wf-imgup[data-wf-image-upload] and the JS replaces it with a clickable preview area. The native input stays hidden, so standard form submissions work with zero changes.

Basic

Drag-and-drop is supported in all shapes. Validation errors (type, file size, and pixel dimensions) are surfaced via WojoToast . An initial server image can be shown via data-wf-preview-src .

JS
import './wf-image-upload.js'
HTML
<!-- Auto-init -->
<div class="wf-imgup" data-wf-image-upload>
  <input type="file" name="avatar" accept="image/*">
</div>

<!-- Manual init -->
<div class="wf-imgup" id="my-uploader">
  <input type="file" name="avatar" accept="image/*">
</div>
<script type="module">
  import { WojoImageUpload } from './wf-image-upload.js'
  const uploader = new WojoImageUpload(document.getElementById('my-uploader')).init()
</script>

Shapes

Set data-wf-shape to one of four values. The default is rounded . All shapes are square aspect ratio except rectangle , which uses a wide 16:9 proportion.

rounded
square
circle
rectangle
HTML
<!-- Rounded corners (default) -->
<div class="wf-imgup" data-wf-image-upload data-wf-shape="rounded">
  <input type="file" name="photo" accept="image/*">
</div>

<!-- Square with minimal radius -->
<div class="wf-imgup" data-wf-image-upload data-wf-shape="square">
  <input type="file" name="logo" accept="image/*">
</div>

<!-- Circle avatar -->
<div class="wf-imgup" data-wf-image-upload data-wf-shape="circle">
  <input type="file" name="avatar" accept="image/*">
</div>

<!-- Rectangle banner (wide aspect ratio) -->
<div class="wf-imgup" data-wf-image-upload data-wf-shape="rectangle">
  <input type="file" name="banner" accept="image/jpeg,image/png,image/webp">
</div>

Sizes

Set data-wf-size to sm or lg . The default medium size is 10rem square ( 18×10rem rectangle). Fine-tune with CSS custom properties .

sm — 6rem
md — 10rem
lg — 14rem
HTML
<div class="wf-imgup" data-wf-image-upload data-wf-shape="circle" data-wf-size="sm">
  <input type="file" name="avatar" accept="image/*">
</div>

<div class="wf-imgup" data-wf-image-upload data-wf-shape="circle">
  <input type="file" name="avatar" accept="image/*">
</div>

<div class="wf-imgup" data-wf-image-upload data-wf-shape="circle" data-wf-size="lg">
  <input type="file" name="avatar" accept="image/*">
</div>

Validation

Client-side validation runs on every file selection and drag-drop. Failures are shown as toast notifications via WojoToast and the input is reset so the same file can be corrected and re-submitted. Three types of checks are available and can be combined freely.

File size

HTML
<!-- Reject files larger than 2 MB (2 097 152 bytes) -->
<div class="wf-imgup" data-wf-image-upload
     data-wf-max-size="2097152">
  <input type="file" name="photo" accept="image/*">
</div>

Pixel dimensions

Min and max width/height are checked after the file passes the size test. Mix and match as needed — any omitted limit defaults to unlimited (0).

HTML
<!-- Banner: at least 400px wide, max 1920×640 -->
<div class="wf-imgup" data-wf-image-upload
     data-wf-shape="rectangle"
     data-wf-min-width="400"
     data-wf-max-width="1920"
     data-wf-max-height="640">
  <input type="file" name="banner" accept="image/jpeg,image/png,image/webp">
</div>

Pre-populate

Use data-wf-preview-src to show the currently saved image on page load — for example when rendering an edit form server-side. No file is staged; the attribute is display-only. The user can then pick a new file to replace it or click the remove button to clear it.

HTML
<div class="wf-imgup" data-wf-image-upload
     data-wf-shape="circle"
     data-wf-preview-src="/uploads/current-avatar.jpg">
  <input type="file" name="avatar" accept="image/*">
</div>

Data Attributes

Place all attributes on the .wf-imgup wrapper element.

Attribute Values / Default Description
data-wf-image-upload Required. Marks the wrapper for auto-init on DOMContentLoaded.
data-wf-shape rounded · square · circle · rectangle
Default: rounded
Preview shape. rectangle uses a wide aspect ratio; all others are square.
data-wf-size sm · lg Size preset. Omit for medium (default). Adjusts the preview area and icon size.
data-wf-max-size integer (bytes)
Default: 0 (unlimited)
Maximum file size in bytes. Files exceeding this limit are rejected with a toast error.
data-wf-max-width integer (px)
Default: 0 (unlimited)
Maximum image width in pixels.
data-wf-max-height integer (px)
Default: 0 (unlimited)
Maximum image height in pixels.
data-wf-min-width integer (px)
Default: 0 (unlimited)
Minimum image width in pixels.
data-wf-min-height integer (px)
Default: 0 (unlimited)
Minimum image height in pixels.
data-wf-preview-src URL string Initial image URL shown on page load (e.g., currently saved server image). Display-only — no File is staged.
data-wf-preview-class CSS class string One or more extra CSS classes added to the .wf-imgup-preview element.
data-wf-disabled Disables the control and mirrors disabled on the native input.
Show More

Native input attributes

Placed on the <input type="file"> inside the wrapper. The multiple attribute is always removed — this component is single-file only.

Attribute Description
accept Restrict the file picker and validate dropped files. Defaults to image/* if omitted. Accepts MIME types (image/jpeg), wildcards (image/*), or extensions (.jpg).
disabled Also disables the component UI.
name Used for normal form submission.

CSS Custom Properties

These properties are declared on :root and can be overridden on .wf-imgup or any ancestor.

CSS
.wf-imgup {
  --wf-imgup-size:       12rem;   /* square size  */
  --wf-imgup-rect-w:     22rem;   /* rectangle width  */
  --wf-imgup-rect-h:     12rem;   /* rectangle height */
  --wf-imgup-border:     #d0d0d0;
  --wf-imgup-bg:         #f5f5f5;
  --wf-imgup-overlay-bg: rgba(0,0,0,.5);
  --wf-imgup-speed:      .15s;
}
Property Default Description
--wf-imgup-size 10rem Width and height of square shapes (rounded, square, circle). Overridden by sm/lg presets.
--wf-imgup-rect-w 18rem Width of the rectangle shape.
--wf-imgup-rect-h 10rem Height of the rectangle shape.
--wf-imgup-border var(--wf-border) Dashed border color of the preview area.
--wf-imgup-bg var(--wf-surface-subtle) Background of the preview area when empty.
--wf-imgup-overlay-bg rgba(0,0,0,.45) The background of the hover overlay is shown when an image is loaded.
--wf-imgup-speed .2s Transition duration for hover, drag, and image fade effects.
--wf-imgup-ease ease Transition easing function.

Programmatic API

After initialization the instance is stored on the wrapper element as el._wfImageUpload .

JS
const el = document.querySelector('[data-wf-image-upload]')
const uploader = el._wfImageUpload

uploader.setPreviewUrl('/uploads/saved.jpg') // show server image
uploader.getFile()                           // returns File or null
uploader.clear()                             // remove preview & reset
uploader.setDisabled(true)                   // disable
uploader.destroy()                           // remove listeners & revoke URL
Method Returns Description
setPreviewUrl(url) Show a remote or server image URL as the preview. Clears any currently staged local File. Does not fire events.
getFile() File | null Returns the currently staged File, or null if only a remote URL is shown or the control is empty.
clear() Remove the preview image, reset the native input, and fire wf:image-remove.
setDisabled(bool) Enable or disable the component and the underlying native input.
destroy() Remove all event listeners and revoke any pending object URL.

Events

Both events are dispatched on the .wf-imgup wrapper and bubble up the DOM.

JS
const el = document.querySelector('[data-wf-image-upload]')

el.addEventListener('wf:image-change', e => {
  console.log('New image file:', e.detail.file)
  // e.detail.file is the validated File object
})

el.addEventListener('wf:image-remove', () => {
  console.log('Image was cleared')
})
Event detail Fired when
wf:image-change { file } A new image passes all validation and its preview is shown. file is the File object.
wf:image-remove The preview image is cleared by the remove button or by calling clear().

i18n

Register a locale globally with WojoI18n before DOMContentLoaded . Any key you omit falls back to the built-in English default. Use {max} in error size messages and {min} / {max} in dimension messages.

JS
import { WojoI18n } from './wf-base.js'

WojoI18n.setLocale('fr')
WojoI18n.register('fr', {
  imageUpload: {
    chooseLabel:      'Choisir une image',
    changeLabel:      'Changer l\'image',
    removeLabel:      'Supprimer',
    placeholderLabel: 'Cliquez ou déposez une image',
    errorType:        'Type de fichier invalide.',
    errorSize:        'Fichier trop volumineux. Max : {max}.',
    errorMinWidth:    'Image trop étroite. Largeur min : {min}px.',
    errorMinHeight:   'Image trop petite. Hauteur min : {min}px.',
    errorMaxWidth:    'Image trop large. Largeur max : {max}px.',
    errorMaxHeight:   'Image trop haute. Hauteur max : {max}px.',
  }
})
HTML
<!-- Per-instance overrides (highest priority) -->
<div class="wf-imgup" data-wf-image-upload
     data-wf-i18n-choose-label="Wählen Sie ein Bild"
     data-wf-i18n-placeholder-label="Klicken oder ablegen"
     data-wf-i18n-error-size="Datei zu groß. Max: {max}.">
  <input type="file" name="avatar" accept="image/*">
</div>

i18n keys

Key data-wf-i18n-* attribute Default (English)
chooseLabel data-wf-i18n-choose-label Choose an image (aria-label when empty)
changeLabel data-wf-i18n-change-label Change image (aria-label when filled)
removeLabel data-wf-i18n-remove-label Remove (aria-label for × button)
placeholderLabel data-wf-i18n-placeholder-label Click or drop the image
errorType data-wf-i18n-error-type Invalid file type.
errorSize data-wf-i18n-error-size File is too large. Max: {max}.
errorMinWidth data-wf-i18n-error-min-width Image is too narrow. Min width: {min}px.
errorMinHeight data-wf-i18n-error-min-height Image is too short. Min height: {min}px.
errorMaxWidth data-wf-i18n-error-max-width Image is too wide. Max width: {max}px.
errorMaxHeight data-wf-i18n-error-max-height Image is too tall. Max height: {max}px.

Class Reference

All modifier classes available on .wf-imgup

Class Description
wf-imgup Root wrapper. Add data-wf-image-upload for auto-init. JS sets data-wf-has-image when a preview is loaded and data-wf-dragging during active drag.
wf-imgup--rounded Shape modifier — large rounded corners (default). Applied by JS based on data-wf-shape.
wf-imgup--square Shape modifier — minimal border radius.
wf-imgup--circle Shape modifier — 50% radius. Placeholder text is hidden in this variant.
wf-imgup--rectangle Shape modifier — wide aspect ratio, sized by --wf-imgup-rect-w and --wf-imgup-rect-h.
wf-imgup-preview The clickable preview area (also the drag-and-drop target). Has role="button" and keyboard support. Opening the file picker and showing the overlay are handled here.
wf-imgup-img The <img> element inside the preview. Hidden (opacity:0) when empty; fades in when data-wf-has-image is set.
wf-imgup-placeholder Icon and text are shown when no image is loaded. Fades out when an image is set.
wf-imgup-placeholder-icon Image icon inside the placeholder.
wf-imgup-placeholder-text “Click or drop image” text inside the placeholder. Hidden for the circle shape.
wf-imgup-overlay Semi-transparent overlay with a camera icon. Visible on hover/focus when an image is loaded, indicating the preview is clickable to change.
wf-imgup-remove Small circular × button positioned in the top-right corner of the preview. Hidden (display:none) when no image is loaded; shown when data-wf-has-image is set.
Show More