In this tutorial, we’ll build a simple file upload component in Vue.js using the Composition API. It will:
changed
event with an array of the selected File
objects whenever the user adds or removes a file.If you want to learn about developing a more robust file upload component including features like:
Then checkout our comprehensive course File Uploads in Vue.js.
The first step in creating any file upload component is to create an HTML file input element.
<!-- FileInput.vue -->
<script setup lang="ts"></script>
<template>
<input type="file" />
</template>
It can optionally accept multiple files with the multiple
attribute.
<input type="file" multiple />
Or we can make multiple
a prop to give control to the consuming component.
<!-- FileInput.vue -->
<script setup lang="ts">
const props = defineProps<{
multiple?: boolean;
}>();
</script>
<template>
<input type="file" :multiple="multiple" />
</template>
Out of the box, the file input is not very pretty and it’s not very easily styled. We can work around this by taking advantage of the default behavior of labels.
When a label is clicked, the browser will focus the file input. So let’s hide the ugly file input and use a label styled as a button to trigger the file selection.
<label for="file-input" class="btn">
Upload File
</label>
<input id="file-input" type="file" hidden />
In order to capture the files that the user selects, we can listen for the change
event on the file input.
<input type="file" multiple @change="handleFileSelect" />
Selected files are available on the files
property of the event target.
function handleFileSelect(e: Event) {
const input = e.target as HTMLInputElement;
const filesAsArray = Array.from(input?.files || []);
}
To render the selected files in the UI and emit the selected files when the user adds or removes a file, we can store the files in a reactive array (a Vue.js ref).
const files = ref<File[]>([]);
That means we should push the selected files to the files
in the handleFileSelect
function.
function handleFileSelect(e: Event) {
const input = e.target as HTMLInputElement;
const filesAsArray = Array.from(input?.files || []);
files.value = files.value.concat(filesAsArray);
}
To render the selected files in the UI, we can simply loop over the files
ref and render a list item for each file.
<template>
<ul>
<li v-for="file in files" :key="file.name">
{{ file.name }}
</li>
</ul>
</template>
To inform the consuming component when a file is added or removed, we can use the emit
function. First we define the event name and type.
const emit = defineEmits<{
(e: "changed", files: File[]): void;
}>();
Then we watch the files
ref and emit the selected files.
watch(files, (newFiles) => {
emit("changed", newFiles);
});
To remove a file from the list, we can use the splice
method on the files
ref.
function removeFile(index: number) {
files.value.splice(index, 1);
}
Of course, we should also add some UI elements to the template to allow the user to remove a file.
<template>
<ul>
<li v-for="(file, index) in files" :key="file.name">
{{ file.name }}
<button @click="removeFile(index)">Remove</button>
</li>
</ul>
</template>
Now that we have all the pieces, we can put them together to create the complete component.
<template>
<div>
<label for="file-input" class="btn">Upload File</label>
<input
id="file-input"
type="file"
:multiple="multiple"
@change="handleFileSelect"
hidden
/>
<ul>
<li v-for="(file, index) in files" :key="file.name">
{{ file.name }} <button @click="removeFile(index)">Remove</button>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
const props = defineProps<{
multiple?: boolean;
}>();
const files = ref<File[]>([]);
const emit = defineEmits<{
(e: "changed", files: File[]): void;
}>();
function handleFileSelect(e: Event) {
const input = e.target as HTMLInputElement;
const filesAsArray = Array.from(input?.files || []);
files.value = files.value.concat(filesAsArray);
}
function removeFile(index: number) {
files.value.splice(index, 1);
}
</script>
This simple yet functional file upload component demonstrates the power and simplicity of Vue.js with the Composition API. It provides a solid foundation that you can build upon based on your specific needs. Style it however you’d like! With Tailwind CSS, it’s easy to make it look great.
Add more advanced features like:
in our comprehensive course File Uploads in Vue.js! Don’t miss it!
Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.
More than 200.000 users have already joined us. You are welcome too!
© All rights reserved. Made with ❤️ by BitterBrains, Inc.