28 CSS Input Fields15 / 28

Pure CSSMIT licensed

File Drop Zone

Drag-and-drop file input with a custom dashed boundary. Native <input type="file"> underneath, the visible filename appearing via `:has()` — accessible, keyboard-friendly, and minimal.

Published

Live Demo
Try it

The code

<label class="if-15">
  <input type="file" name="upload" accept="image/*,.pdf" />
  <span class="if-15-icon" aria-hidden="true">
    <svg
      viewBox="0 0 24 24"
      width="22"
      height="22"
      fill="none"
      stroke="currentColor"
      stroke-width="1.6"
      stroke-linecap="round"
      stroke-linejoin="round"
    >
      <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
      <polyline points="17 8 12 3 7 8" />
      <line x1="12" y1="3" x2="12" y2="15" />
    </svg>
  </span>
  <span class="if-15-text">
    <strong>Click to upload</strong> or drag &amp; drop
    <span class="if-15-types">PNG, JPG, or PDF · max 10 MB</span>
  </span>
</label>
.if-15 {
  position: relative;
  display: block;
  width: 100%;
  max-width: 320px;
  cursor: pointer;
  border: 1.5px dashed rgba(99, 102, 241, 0.5);
  border-radius: 12px;
  padding: 22px 18px;
  background: rgba(99, 102, 241, 0.05);
  text-align: center;
  transition: border-color 0.2s, background 0.2s, transform 0.15s;
}

.if-15:hover {
  border-color: #818cf8;
  background: rgba(99, 102, 241, 0.1);
}

.if-15:focus-within {
  border-color: #818cf8;
  background: rgba(99, 102, 241, 0.12);
  box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.18);
}

.if-15 input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.if-15-icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin: 0 auto 8px;
  border-radius: 10px;
  background: rgba(99, 102, 241, 0.18);
  color: #a5b4fc;
}

.if-15-text {
  display: block;
  font-size: 13px;
  color: #c8c0ff;
}

.if-15-text strong {
  color: #a5b4fc;
  font-weight: 600;
}

.if-15-types {
  display: block;
  font-size: 11px;
  color: #b8b6d4;
  margin-top: 4px;
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Input Field from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: File Drop Zone
Source: https://codefronts.com/components/css-input-fields/file-drop-zone/

Drag-and-drop file input with a custom dashed boundary. Native <input type="file"> underneath, the visible filename appearing via `:has()` — accessible, keyboard-friendly, and minimal.
## HTML
```html
<label class="if-15">
  <input type="file" name="upload" accept="image/*,.pdf" />
  <span class="if-15-icon" aria-hidden="true">
    <svg
      viewBox="0 0 24 24"
      width="22"
      height="22"
      fill="none"
      stroke="currentColor"
      stroke-width="1.6"
      stroke-linecap="round"
      stroke-linejoin="round"
    >
      <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
      <polyline points="17 8 12 3 7 8" />
      <line x1="12" y1="3" x2="12" y2="15" />
    </svg>
  </span>
  <span class="if-15-text">
    <strong>Click to upload</strong> or drag &amp; drop
    <span class="if-15-types">PNG, JPG, or PDF · max 10 MB</span>
  </span>
</label>
```
## CSS
```css
.if-15 {
  position: relative;
  display: block;
  width: 100%;
  max-width: 320px;
  cursor: pointer;
  border: 1.5px dashed rgba(99, 102, 241, 0.5);
  border-radius: 12px;
  padding: 22px 18px;
  background: rgba(99, 102, 241, 0.05);
  text-align: center;
  transition: border-color 0.2s, background 0.2s, transform 0.15s;
}

.if-15:hover {
  border-color: #818cf8;
  background: rgba(99, 102, 241, 0.1);
}

.if-15:focus-within {
  border-color: #818cf8;
  background: rgba(99, 102, 241, 0.12);
  box-shadow: 0 0 0 3px rgba(129, 140, 248, 0.18);
}

.if-15 input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.if-15-icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin: 0 auto 8px;
  border-radius: 10px;
  background: rgba(99, 102, 241, 0.18);
  color: #a5b4fc;
}

.if-15-text {
  display: block;
  font-size: 13px;
  color: #c8c0ff;
}

.if-15-text strong {
  color: #a5b4fc;
  font-weight: 600;
}

.if-15-types {
  display: block;
  font-size: 11px;
  color: #b8b6d4;
  margin-top: 4px;
}
```

How this works

The wrapper label uses a dashed border and centered icon plus text; a real file input is absolutely positioned with inset:0 and opacity:0, so it covers the entire drop zone while remaining invisible. Because the input is the top layer, native drag-and-drop, click-to-open, and keyboard focus all work without JavaScript — the browser fires the file picker or accepts the dropped file directly on the input.

Visual states are pure CSS: :hover and :focus-within tint the border and background, and accept filters the picker to images and PDF. This is a zero-KB replacement for Dropzone.js (about 43KB) and react-dropzone (about 18KB) for the common single-file upload case.

Make it yours

  • Change accept to restrict file types — for example accept=".csv,.xlsx" for spreadsheet uploads.
  • Add the multiple attribute on the input to accept several files in one drop.
  • Tune the dashed border colour, radius, and padding to match your brand accent.
  • Swap the SVG glyph or copy inside the label — the invisible input still catches every event.

Gotchas — read before shipping

  • The overlay input must have opacity:0, not display:none, or drag events and the picker will stop firing.
  • Pure CSS cannot show the chosen filename — wire a tiny change listener if you need to echo it back to the user.
  • The 10 MB limit shown in the label is copy only; enforce it server-side and with a JS size check on change.

Browser support

ChromeSafariFirefoxEdge
60+12+60+60+

Native file input with drag-and-drop works everywhere; no library, no polyfill.

Search CodeFronts

Loading…