I made this, code below:

I know I am late to the party and actually replying with a component in vue3 but maybe it will still help someone. It’s a file input component, you can add emits to it if u prefer I just take the data on form submit from the parent component with this.$refs.fileUploadRef.fileUplaoded
<template>
<ion-item button="true" :detail="false" :disabled=disabled>
<ion-icon v-if="prependIcon" slot="start" color="primary" :src="prependIcon"></ion-icon>
<ion-label @click="openInput">
<div v-if="label" class="input-label">{{ label }}</div>
<ion-note>{{ fileUploaded?.name || placeholder || "" }}</ion-note>
<input ref="fileUpload" type="file" class="d-none" :accept="inputAccepts" @change="onInputChange" />
</ion-label>
<ion-button v-if="clearable" slot="end" color="clear" @click="clearInput">
<ion-icon slot="icon-only" :src="getIcon('close.svg')"></ion-icon>
</ion-button>
</ion-item>
</template>
<script>
import { getIcon } from "@/utils_funcs"
import { IonButton, IonIcon, IonItem, IonLabel, IonNote } from "@ionic/vue"
export default {
components: {
IonItem,
IonIcon,
IonLabel,
IonButton,
IonNote,
},
props: {
prependIcon: {
type: String,
required: false,
default: getIcon("camera.svg"),
},
inputAccepts: {
type: String,
required: false,
default: "image/png, image/jpeg, image/jpg, image/heic, image/bmp",
},
label: {
type: String,
required: false,
default: "",
},
placeholder: {
type: String,
required: false,
default: "",
},
clearable: {
type: Boolean,
required: false,
default: false,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
fileUploaded: null,
}
},
methods: {
getIcon,
openInput() {
this.$refs.fileUpload.click()
},
onInputChange(ev) {
this.fileUploaded = ev.target.files[0]
},
clearInput(_ev) {
this.$refs.fileUpload.value = ""
this.fileUploaded = null
},
},
}
</script>
<style scoped>
ion-item {
--inner-padding-end: 0;
}
ion-item::part(native) {
padding: 0;
}
.input-label {
font-size: 13px;
padding-bottom: 5px;
}
</style>
d-none is display:none, if u use ionic icons just rewrite the ion-icon accordingly. My getIcon func is this
export function getIcon(iconName) {
return new URL(`/src/assets/icons/${iconName}`, import.meta.url).href
}
and then on the parent component u can simply do something like
<file-input ref="fileUploadRef" :clearable="true" label="Přední strana produktu" placeholder="Prázdné" />
happy coding