input type=file + FormData + fetch
File Uploads
Handle file selection, preview, and multipart upload using built-in browser APIs. No library required for the basics.
What you'll learn
- Read selected files from the change event
- Preview an image with createObjectURL
- Send the file via FormData and fetch
File inputs work a little differently from other inputs — you cannot use v-model on them. Read files from the change event, then upload with FormData.
Reading the Selected File
<script setup lang="ts">
import { ref } from 'vue'
const file = ref<File | null>(null)
function onPick(e: Event) {
const input = e.target as HTMLInputElement
file.value = input.files?.[0] ?? null
}
</script>
<template>
<input type="file" @change="onPick" />
<p v-if="file">Picked: {{ file.name }} ({{ file.size }} bytes)</p>
</template> Image Preview
For images, build a local preview URL with URL.createObjectURL. Revoke it when the component unmounts to free memory.
<script setup lang="ts">
import { ref, computed, onBeforeUnmount } from 'vue'
const file = ref<File | null>(null)
const previewUrl = computed(() =>
file.value ? URL.createObjectURL(file.value) : ''
)
onBeforeUnmount(() => {
if (previewUrl.value) URL.revokeObjectURL(previewUrl.value)
})
</script>
<template>
<input type="file" accept="image/*" @change="e => file = (e.target as HTMLInputElement).files?.[0] ?? null" />
<img v-if="previewUrl" :src="previewUrl" alt="preview" />
</template> Uploading
Bundle the file into FormData and post it. Do not set the Content-Type header yourself — the browser fills in the multipart boundary.
async function upload(file: File) {
const fd = new FormData()
fd.append('file', file)
fd.append('caption', 'My photo')
const res = await fetch('/api/upload', { method: 'POST', body: fd })
if (!res.ok) throw new Error(await res.text())
return res.json()
} Multiple Files
Add the multiple attribute and iterate input.files:
<input type="file" multiple @change="onPickMany" /> function onPickMany(e: Event) {
const list = (e.target as HTMLInputElement).files
if (!list) return
for (const f of Array.from(list)) {
upload(f)
}
}