Selector & list appearance axes, card sizes, popover, files-inside, single vs multiple, accept patterns
The visual surface is split into three independent attributes you can combine freely:
selector-appearance โ card ยท button ยท minimal ยท (what the user clicks/drops onto)list-appearance โ list ยท detailed ยท grid ยท badges ยท popover ยท none ยท (where picked files appear)card-size โ minimal ยท compact ยท big ยท (density of the card selector)The legacy single-axis display-mode attribute is still supported as a shorthand โ see the bottom of this page.
controls + item-controls)Two Plyr-style allowlists. controls picks which top-level surfaces render; item-controls picks which parts of each file row render. Both are comma-separated; when an attribute is absent everything renders. Toggle the boxes and watch the dropzone recompose live โ add a file to see the progress parts animate.
Count- or state-based progress behaviour doesn't need dedicated attributes โ compose it from the primitives above plus the change event and auto-upload. Two common asks:
progress token toggles.
const dz = document.getElementById('recipe-count')
const LEAN = 'icon,name,size,type,status,action,remove' // no progress
dz.addEventListener('change', () => {
const want = dz.files.length >= 4 ? null : LEAN
// skip no-op writes; `change` fires on selection changes only, so no loop
if (dz.getAttribute('item-controls') === want) return
want === null ? dz.removeAttribute('item-controls')
: dz.setAttribute('item-controls', want)
})
auto-upload="false" files sit pending and the strip stays hidden (hasActivity is false) until you kick off the upload โ no extra config, it's the default gate.
<web-dropzone auto-upload="false" ...></web-dropzone>
// files added โ pending โ global strip hidden (hasActivity = false)
startBtn.addEventListener('click', () => dz.uploadAll())
// upload starts โ strip appears on its own
selector-appearance)Four visual entry points for picking files.
select-files-text and no-file-chosen-text.
list-appearance.
list-appearance)How the picked files are presented. Six options ranging from a simple vertical list to badge-style pills or a hidden popover.
web-multiselect badges. Default: file-type icons in the pill. Set show-thumbnails for image previews, or override --dz-badge-icon-size: 0 to hide the slot entirely.
Grid mode is almost entirely CSS-variable driven. Drop a few images below, then move the sliders to reshape the grid in real time. The panel writes the same --dz-* custom properties you'd set in your own CSS โ the live readout is copy-pasteable.
Switch grid-layout to natural for a justified photo gallery: mixed portrait/landscape images share one row height (--dz-preview-row-height) and keep their own aspect ratio โ nothing cropped or stretched. In uniform layout, object-fit chooses crop (cover) vs. fit (contain). Set grid-status="overlay" and let a file finish uploading to see the light veil + big centred check/error glyph.
card-size)Density variants for the card selector. Only meaningful when selector-appearance="card".
files-inside)Render the file list inside the dropzone area instead of below it. Useful when vertical space is constrained or when you want a unified container look.
Mixing the three axes covers the patterns users actually want โ toolbars, attachment fields, marketing landings, and more.
summary-template)When list-appearance="popover" the summary line supports {count} and {size} placeholders โ quick customization without writing JS. For richer summaries (pluralization, badges) use renderSummaryCallback; see Structural Rendering.
popover-placement)Positioning uses Floating UI, so it auto-flips on viewport collisions. The attribute sets the preferred initial placement.
display-mode shorthandThe original single-axis attribute still works as a shorthand. When both are set, the orthogonal attribute wins.
display-mode="list" โ selector-appearance="card" + list-appearance="list"display-mode="detailed" โ card + detaileddisplay-mode="grid" โ card + griddisplay-mode="compact" โ card + popoverThe multiple attribute defaults to true. Set multiple="false" to lock to a single file (subsequent drops replace the existing selection).
The accept attribute uses the same syntax as the native <input type="file">: comma-separated MIME types, MIME wildcards, or file extensions.
Files that don't match accept are rejected at validation time and surface via the files-rejected event โ see Validation.
The disabled attribute follows HTML convention: presence enables it, ="false" overrides.
Methods and events let you drive the dropzone from your own code.
(none yet โ drop or pick a file)
const el = document.getElementById('api-demo')
el.addEventListener('file-added', e => console.log('added', e.detail))
el.addEventListener('file-removed', e => console.log('removed', e.detail))
el.addEventListener('files-rejected', e => console.log('rejected', e.detail))
el.addEventListener('change', e => console.log('change', e.detail))
el.addFiles(fileList) // programmatic add (FileList or File[])
el.removeFile(id) // remove by FileState.id
el.clear() // remove all
const files = el.files // current FileState[]