vue-picture-input: a photo picker that fits the mobile web
Mobile-friendly picture file input component for Vue.js 2-3 with image preview, drag and drop, EXIF orientation, and more
At a glance
- What is it?
- vue-picture-input is a single-file Vue component that turns a file input into a tappable image preview with drag and drop, cropping and EXIF orientation handling, written for Vue 2.7 and Vue 3. It ships as one .vue file and one MIT licence, with no runtime dependency to argue about.
- Who is it for?
- Use vue-picture-input when you need a user-facing photo picker that feels native on a phone and you want it inside a Vue application without pulling in an upload library, because the whole component is one .vue file you can read in a sitting. Do not use it as the upload mechanism itself, since the component hands you an image object and a FileReader warning rather than posting anything anywhere.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 66 days ago.
- What is it written in?
- Mainly Vue, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One file, no runtime dependency, Vue 2 and Vue 3 together
The whole component ships as a single file. The package main points at PictureInput.vue at the root of the repository, and the published files list contains dist, PictureInput.vue, README.md and LICENSE. There is no runtime dependency block in package.json at all, only peerDependencies declaring vue as ^2.7.0 || ^3.0.0, which is an unusual and pleasant thing to find in a component: nothing else is dragged into your bundle. The compatibility note explains the arrangement. The component is written in Vue 2 style using the Options API, but it is compatible with Vue 3, and the README shows the same template working under both a classic export default block and a script setup block with refs. For a codebase mid-migration between Vue 2 and Vue 3, that dual support is the feature that matters most.
Installing from npm, yarn or straight from a CDN
The install is a single command for either of the two common package managers.
npm install --save vue-picture-inputyarn add vue-picture-inputFor a quick look without a build step, the component is also reachable through unpkg's CDN or jsDelivr, and the README carries a complete standalone HTML page that loads Vue 2 from unpkg, loads the built UMD bundle and registers the component. The package metadata names the browser builds explicitly, with unpkg pointing at dist/vue-picture-input.umd.js and jsdelivr pointing at the same file. There is also a CodeSandbox example project linked from the README for trying the component in a running sandbox rather than in your own project.
The template is the whole API surface
Using the component means placing a picture-input element and listening for its change event. The README's example gives width, height, margin, accept, size and button-class, plus a custom-strings object for the upload and drag labels, and a change handler that receives the selected picture.
<picture-input
ref="pictureInput"
width="600"
height="600"
margin="16"
accept="image/jpeg,image/png"
size="10"
button-class="btn"
@change="onChange">
</picture-input>The handler is where the interesting behaviour shows up. When an image is available the component hands you the picture, and when it is not, the README example logs a message saying the FileReader API is not supported and to use the form instead. So the component degrades to null rather than throwing, and it tells the developer what happened instead of silently doing nothing. The same element also works with the Composition API, where the picture goes into a ref instead of a data property, and the component instance itself is held in a ref when you need to call into it.
Cropping changes the preview, never the uploaded file
The crop prop is the one most likely to be misunderstood, so the README spells out the boundary. By default cropping is on, and the image is resized and centred to cover the preview container. Setting crop to false resizes and centres the image so it is fully contained instead. What matters is the caveat that follows: this only affects the image preview, the image file will not be cropped. So if your backend needs a square thumbnail or a specific aspect ratio, the component will not produce it for you. The related props are toggleAspectRatio, which shows a button for switching the canvas between landscape and portrait on a non-square canvas, and autoToggleAspectRatio, which makes that switch happen automatically to match the picture the user picked. Between them they cover the case where the preview container and the source image disagree about shape.
Twenty-odd props for preview shape, labels and file limits
The props list is long but falls into a few groups. Preview geometry: width and height set the maximum size of the preview container in pixels, with the picture resized and centred to cover it, the container expanding to full width if width is omitted, and height defaulting to equal to width if omitted. margin sets the margin around the container and radius sets its border-radius, where a value of 50 gives a circular container, and plain removes the inner border and text. File constraints: accept sets the accepted media types and defaults to image/*, size sets the maximum accepted file size in megabytes, and alertOnError, on by default, controls whether an alert appears when someone selects a file of the wrong type or too large. Labels and buttons: removable shows a Remove Photo button, hideChangeButton hides the Change Photo button, and buttonClass and removeButtonClass set their classes, with the defaults being btn btn-primary button and btn btn-secondary button secondary.
Prefill shows a picture without filling the input
The prefill prop takes an image url or a File object and displays it in the preview. The README attaches an explicit warning to it: prefill does not change the underlying file input value, and it should be used for the image preview only. That distinction is the kind of thing that turns into a support ticket if you forget it. A form that displays the existing avatar of a user editing their profile will submit an empty file input, because prefill never touched it. There is a companion prop, prefillOptions, for the case where you prefill with a data uri and want to specify a file name and a media or file type, with the file name, file type and media type given as separate keys.
Capture from the camera and the CDN story
One prop targets the phone case directly: capture, which you use if you want to allow image capture from capture devices such as a camera. Combined with the mobile-friendly design and the changeOnClick behaviour, which opens the image selector when the user clicks on the image and is on by default, that is what makes the component feel like a native photo picker rather than a styled file field. The component also solves the layout problem that a fixed file input creates in a modal: the zIndex prop sets the base z-index value, and the README says to change it if you have issues with your layout, with a default of 10000. It is a blunt instrument, but it is the kind of knob you need when a dropdown or a sticky header covers your preview.
What this component does not do for you
Three limits are worth stating before you adopt it. It does not upload anything. The change event gives you the picture and leaves transport, validation on the server and progress reporting entirely to you. It does not resize the file itself, since cropping affects only the preview, so a 12 megapixel phone photo goes to your backend at full size unless you compress it somewhere else. And it does not crop the file either, which is the same limitation from the other side. On the build side, the project is a small Vue 2 era package whose most recent release is v4.0.2 from 2025-07-21, preceded by v3.0.1 and v3.0.0 in July 2023, and the last push to the repository was on 2026-08-18, so it is being touched without a new tag. The development stack is Vite for building and dev serving, Jest with jsdom and @vue/test-utils for tests, and vue-jest for the single-file components, with the licence field on the repository saying MIT.
Editorial conclusion
Use vue-picture-input when you need a user-facing photo picker that feels native on a phone and you want it inside a Vue application without pulling in an upload library, because the whole component is one .vue file you can read in a sitting. Do not use it as the upload mechanism itself, since the component hands you an image object and a FileReader warning rather than posting anything anywhere. Verify first that your project runs Vue 2.7 or Vue 3, that the accept list you set matches what your backend validates, and that the prefill behaviour you rely on is preview only, since the README is explicit that it does not change the underlying file input value.
Frequently asked questions
How do I install vue-picture-input?
Install it from npm with npm install --save vue-picture-input, or from yarn with yarn add vue-picture-input. You can also load the built UMD file directly from unpkg or jsDelivr in a standalone HTML page.
Does vue-picture-input work with Vue 3?
Yes. The component is written in Vue 2 style with the Options API but is compatible with Vue 3, and the README shows the same template used from a script setup block with refs. The peer dependency is declared as vue ^2.7.0 || ^3.0.0.
Does the crop option actually crop the uploaded file?
No. The README is explicit that cropping only affects the image preview and that the image file will not be cropped. The file you get is the original file the user selected.
What is the difference between prefill and the file input value?
Prefill only fills the image preview. The README states that it does not change the underlying file input value and should be used for the image preview only, so a prefilled form still submits an empty file input.
How do I limit which files and how large they can be?
Use the accept prop for the accepted media types, which defaults to image/*, and the size prop for the maximum accepted file size in megabytes. The alertOnError prop, on by default, controls the alert shown when a file of the wrong type or too large is selected.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/alessiomaffeis-vue-picture-input)Was this useful?