โ† Back to Examples

๐ŸŽ›๏ธ Display & Composition

Selector & list appearance axes, card sizes, popover, files-inside, single vs multiple, accept patterns

DC01 ยท Display: three orthogonal axes

The visual surface is split into three independent attributes you can combine freely:

The legacy single-axis display-mode attribute is still supported as a shorthand โ€” see the bottom of this page.

DC02 ยท Composable controls (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.

Live:
controls โ€” surfaces
item-controls โ€” row parts
Unchecking every box in a group is the same as removing the attribute โ€” the default (render all) applies. Count- or state-based progress rules aren't extra attributes โ€” compose them from these primitives; see the recipes below.

DC03 ยท Recipes โ€” progress rules in userland

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:

Per-row bars only at 4+ files (count-based)

1โ€“3 files โ†’ global strip only. 4+ โ†’ both bars. The global strip is untouched; only the per-row 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)
})

Global strip only after upload starts (state-based)

With 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

DC04 ยท Selector Appearance (selector-appearance)

Four visual entry points for picking files.

Click anywhere on the card to browse, or drag-and-drop files.
Use when the picker should sit inline (toolbars, dense forms).
Compact 36ร—36 button. The badge appears when files are picked.
Mirrors the modern browser look. Empty: "No file chosen" ยท 1 file: filename ยท multiple: "N files chosen". Customize via select-files-text and no-file-chosen-text.
The native label shows a summary; the full list still renders below per list-appearance.
Both labels are i18n-friendly.

DC05 ยท 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.

Same surface as 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.
Popover header shows file count + Add more / Clear all, with a limits hint underneath. Footer pins total size.
Picked: (none)
Submit blocked by native form validity until at least 2 files โ‰ฅ 1 KB are selected.

DC06 ยท Grid tuning โ€” live controls

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.

No images handy? Any file works โ€” non-images fall back to a type icon tile, the geometry still reshapes.
columns
mode
min tile 120px
columns 4
tile
gap 12px
aspect-ratio
border-radius 6px
layout & fit
grid-layout
object-fit
row-height 160px
grid-status
count & height
max-visible-files 24
list-max-height none

DC07 ยท Card Size (card-size)

Density variants for the card selector. Only meaningful when selector-appearance="card".

DC08 ยท Files-Inside Layout (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.

DC09 ยท Common combinations

Mixing the three axes covers the patterns users actually want โ€” toolbars, attachment fields, marketing landings, and more.

Slack/Gmail-style attachment pattern.
Click icon โ†’ opens picker. After files exist โ†’ click toggles popover.

DC10 ยท Summary Template (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.

DC11 ยท Popover Placement (popover-placement)

Positioning uses Floating UI, so it auto-flips on viewport collisions. The attribute sets the preferred initial placement.

DC12 ยท Legacy display-mode shorthand

The original single-axis attribute still works as a shorthand. When both are set, the orthogonal attribute wins.

DC13 ยท Single vs Multiple

The multiple attribute defaults to true. Set multiple="false" to lock to a single file (subsequent drops replace the existing selection).

DC14 ยท Accept Patterns

The accept attribute uses the same syntax as the native <input type="file">: comma-separated MIME types, MIME wildcards, or file extensions.

Tip

Files that don't match accept are rejected at validation time and surface via the files-rejected event โ€” see Validation.

DC15 ยท Disabled State

The disabled attribute follows HTML convention: presence enables it, ="false" overrides.

DC16 ยท Programmatic API

Methods and events let you drive the dropzone from your own code.

Events:
(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[]