JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://raw.githubusercontent.com/lhorie/mithril.js/components/mithril.js"></script>

CSS

.uploader {border:1px dashed #888;height:100px;}

JavaScript

var Uploader = {
	upload: function(options) {
		var formData = new FormData
		for (var key in options.data) {
			for (var i = 0; i < options.data[key].length; i++) {
				formData.append(key, options.data[key][i])
			}
		}

		//simply pass the FormData object intact to the underlying XMLHttpRequest, instead of JSON.stringify'ing it
		options.serialize = function(value) {return value}
		options.data = formData

		return m.request(options)
	},
	serialize: function(files) {
		var promises = files.map(function(file) {
			var deferred = m.deferred()

			var reader = new FileReader
			reader.readAsDataURL(file)
			reader.onloadend = function(e) {
				deferred.resolve(e.result)
			}
			reader.onerror = deferred.reject
			return deferred.promise
		})
		return m.sync(promises)
	},
	controller: function(args) {
		this.noop = function(e) {
			e.preventDefault()
		}
		this.update = function(e) {
			e.preventDefault()
			if (typeof args.onchange == "function") {
				args.onchange([].slice.call((e.dataTransfer || e.target).files))
			}
		}
	},
	view: function(ctrl, args) {
		return m(".uploader", {ondragover: ctrl.noop, ondrop: ctrl.update})
	}
}

//usage demo 2: upload as base-64 encoded data url from a parent form
var Demo2 = {
	Asset: {
		save: function(data) {
			return m.request({method: "POST", url: "/echo/json/", data: data})
		}
	},

	controller: function() {
		var files = m.prop([])
		return {
			files: files,
			save: function() {
				Uploader.serialize(files()).then(function(files) {
					Demo2.Asset.save({files: files}).then(function() {
						alert("Uploaded!")
					})
				})
			}
		}
	},
	view: function(ctrl) {
        return [
			m("h1", "Uploader demo"),
			m("p", "Drag and drop a file below. An alert box will appear when the upload finishes"),
			m("form", [
				m.component(Uploader, {onchange: ctrl.files}),
                ctrl.files().map(function(file) {
					return file.name
				}).join(),
				m("button[type=button]", {onclick: ctrl.save},...