npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@h-k-dev/angular-file-drop

v1.1.1

Published

A lightweight, signal-based Angular directive for drag-and-drop file and folder uploads, with directory traversal and accept-type filtering.

Readme

Angular File Drop

npm version license

A lightweight, signal-based Angular directive for drag-and-drop file and folder uploads — with directory traversal, accept-type filtering, and a click-to-open file picker. No stylesheets, no XHR wrappers, no DOM mutation. Just the File objects.

The Philosophy

Try the live demo →

Dropzone.js is great, but it often fights against modern Angular architecture by injecting its own CSS, mutating the DOM, and hijacking HTTP requests with its own XHR wrappers.

angular-file-drop is the "Angular-only" alternative. It does a portion of what Dropzone does, but strictly the Angular way:

  • Native directive — binds to your existing elements using standard Angular syntax.
  • Headless — handles the messy HTML5 drag-and-drop events and hands you raw File objects.
  • Zero network opinions — you upload with Angular's own HttpClient, keeping interceptors and auth intact.
  • Bring your own UI — no forced stylesheets. Style your dropzone exactly how your app needs it.

Features

  • Drag-and-drop and click-to-open file picker on a single element
  • Recursive folder/directory traversal (modern File System Access API, with legacy webkitGetAsEntry and plain FileList fallbacks)
  • accept-style filtering by extension or MIME (.png, image/*, application/pdf, */*)
  • Single- or multiple-file enforcement
  • Automatic hidden-file filtering (.git, .DS_Store, …)
  • Signal-based drag-over state for easy template styling
  • SSR-safe (guards all browser-only APIs)
  • A ready-made FILE_TYPES map of common accept strings

Installation

npm install @h-k-dev/angular-file-drop

Requires Angular 17.3+ (standalone directives + signals).

Quick Start

The directive is standalone — import AngularFileDrop directly into your component.

import { Component } from '@angular/core';
import { AngularFileDrop, FileDropEvent } from '@h-k-dev/angular-file-drop';

@Component({
  selector: 'app-uploader',
  imports: [AngularFileDrop],
  template: `
    <div
      dropZone
      [class.is-dragging]="zone.isDragOver()"
      (fileDrop)="onDrop($event)"
      #zone="dropZone"
    >
      Drag files here, or click to browse
    </div>
  `,
})
export class UploaderComponent {
  onDrop(event: FileDropEvent) {
    for (const { file, relativePath } of event.files) {
      console.log(relativePath, file.size);
    }
  }
}
.is-dragging {
  outline: 2px dashed #4f46e5;
  background: #eef2ff;
}

Examples

Restrict accepted types

Pass any accept-style string. The FILE_TYPES map provides ready-made values.

import { FILE_TYPES } from '@h-k-dev/angular-file-drop';

@Component({
  imports: [AngularFileDrop],
  template: `
    <div dropZone [acceptedFiles]="accept" (fileDrop)="onDrop($event)">
      Images and PDFs only
    </div>
  `,
})
export class Component {
  accept = `${FILE_TYPES.ANY_IMAGE},${FILE_TYPES.PDF}`; // "image/*,.pdf,application/pdf"
}

You can also write the string by hand: [acceptedFiles]="'.png,.jpg,image/*'".

Single file only

<div dropZone [multiple]="false" (fileDrop)="onDrop($event)">
  Drop a single file
</div>

Drop a whole folder

directory (on by default) recursively walks dropped folders. Each DroppedFile carries a relativePath that preserves the folder structure.

template: `<div dropZone [directory]="true" (fileDrop)="onDrop($event)">Drop a folder</div>`;

onDrop(event: FileDropEvent) {
  // e.g. "photos/2026/holiday/IMG_001.jpg"
  event.files.forEach((f) => console.log(f.relativePath));
}

Open a folder picker on click

Set directoryPicker to make the click-to-open dialog a folder chooser instead of a file chooser.

<div dropZone [directoryPicker]="true">Click to choose a folder</div>

React to drag events and style the zone

The isDragOver signal flips while a valid file drag is over the element. Grab the directive instance via the dropZone export.

<div
  dropZone
  #zone="dropZone"
  [class.active]="zone.isDragOver()"
  (dragEnter)="onEnter($event)"
  (dragLeave)="onLeave($event)"
>
  {{ zone.isDragOver() ? 'Release to upload' : 'Drag files here' }}
</div>

Manual activation (custom button)

Disable the built-in click handling with isManualActivation and open the picker yourself from a child control.

@Component({
  imports: [AngularFileDrop],
  template: `
    <div dropZone #zone="dropZone" [isManualActivation]="true" (fileDrop)="onDrop($event)">
      <p>Drag files here</p>
      <button type="button" (click)="zone.openFilePicker($event)">Browse files</button>
      <button type="button" (click)="zone.openDirectoryPicker($event)">Browse folder</button>
    </div>
  `,
})
export class Component {
  onDrop(event: FileDropEvent) {
    /* ... */
  }
}

Disable the zone

<div dropZone [disabled]="isUploading" (fileDrop)="onDrop($event)">…</div>

Upload with HttpClient

The directive stays out of your network layer — wire it up however you like.

onDrop(event: FileDropEvent) {
  const body = new FormData();
  event.files.forEach((f) => body.append('files', f.file, f.relativePath));
  this.http.post('/api/upload', body).subscribe();
}

API Reference

Inputs

| Input | Type | Default | Description | | ------------------- | --------- | ------- | ------------------------------------------------------------------------------------------- | | multiple | boolean | true | Allow more than one file. When false, only the first file is emitted. | | directory | boolean | true | Recursively traverse dropped folders. | | directoryPicker | boolean | false | Make the click-to-open dialog a folder picker (webkitdirectory) rather than files. | | acceptedFiles | string | '' | accept-style filter, e.g. .png,image/*,application/pdf. Empty accepts everything. | | ignoreHiddenFiles | boolean | true | Drop dotfiles and files inside dot-folders (.git, .DS_Store, …). | | clickable | boolean | true | Open the file picker when the host element is clicked or activated via keyboard. | | disabled | boolean | false | Ignore all drops, clicks, and keyboard activation. | | isManualActivation| boolean | false | Disable built-in click/keyboard activation so you can call the open* methods yourself. |

Outputs

| Output | Payload | Description | | ----------- | ---------------- | ------------------------------------------------------- | | fileDrop | FileDropEvent | Emitted after files are dropped or chosen and filtered. | | dragEnter | DragEvent | A valid file drag entered the element. | | dragOver | DragEvent | A valid file drag is moving over the element. | | dragLeave | DragEvent | A valid file drag left the element. |

Public members

| Member | Description | | ------------------------------- | ------------------------------------------------------------------ | | isDragOver: Signal<boolean> | true while a valid file drag is over the element. | | openPicker(event?, options?) | Open the hidden file input. options.directory toggles folder mode. | | openFilePicker(event?) | Open a file picker. | | openDirectoryPicker(event?) | Open a folder picker. |

Access these in templates via the dropZone export: #zone="dropZone".

Types

interface DroppedFile {
  file: File;
  relativePath: string; // preserves folder structure, e.g. "docs/report.pdf"
}

interface FileDropEvent {
  files: DroppedFile[];
}

Exported utilities

The directive's pure helpers are exported for advanced use and testing: containsFiles, setDropEffect, isHiddenPath, filterHiddenFiles, isFileAccepted, filterAcceptedFiles, enforceMultiple, toDroppedFiles, readDroppedFiles, walkHandles, walkEntries, createHiddenFileInput, and the FILE_TYPES map.

Browser Support

Works in all modern browsers. Folder traversal uses the File System Access API where available and falls back to webkitGetAsEntry and then a plain FileList. Server-side rendering is safe — all browser-only APIs are guarded.

License

MIT © h-k-dev