sodcalculator

10 Tech How-To

How to Upload Images with JavaScript: Step-by-Step

Guide 10-38300 · Updated · Step by step

This guide shows you how to let users select an image file from their device and upload it to a server using plain JavaScript. You’ll learn the core techniques—handling the file input, previewing the image, and sending it via AJAX—without needing any libraries. By the end, you’ll have a working upload flow that you can adapt to your own backend.

What You’ll Need

  • A basic HTML file with a form or input element.
  • A text editor (like VS Code, Sublime, or Notepad++).
  • A web browser with developer tools (Chrome, Firefox, Edge).
  • A server endpoint that accepts file uploads (for the final step). For testing, you can use a local server like XAMPP, or a service like httpbin.org/upload (though it won’t store your file).

Step-by-Step

  1. Create the HTML structure. Start with a simple file input and a preview area. The input should accept only image files for a better user experience.
    <input type="file" id="imageInput" accept="image/*">
    <img id="preview" alt="Preview" style="max-width: 200px; display: none;">
    <button id="uploadBtn" style="display: none;">Upload</button>
  2. Add the JavaScript event listener. In your script, listen for the ‘change’ event on the file input. This fires when the user selects a file.
    const input = document.getElementById('imageInput');
    const preview = document.getElementById('preview');
    const uploadBtn = document.getElementById('uploadBtn');
    
    input.addEventListener('change', handleFileSelect);
  3. Handle the file selection. In the handler, check that a file was actually selected, and that it’s an image. Then create a temporary URL for the file to display a preview.
    function handleFileSelect(event) {
      const file = event.target.files[0];
      if (!file) return;
      
      if (!file.type.startsWith('image/')) {
        alert('Please select an image file.');
        return;
      }
    
      // Show preview
      const objectURL = URL.createObjectURL(file);
      preview.src = objectURL;
      preview.style.display = 'block';
      uploadBtn.style.display = 'inline-block';
    }
  4. Set up the upload button. Add a click listener to the button that will send the file to the server.
    uploadBtn.addEventListener('click', uploadImage);
  5. Write the upload function. Use the Fetch API to send the file as FormData. This is the modern, clean way to upload files.
    async function uploadImage() {
      const file = input.files[0];
      if (!file) return;
    
      const formData = new FormData();
      formData.append('image', file);
    
      try {
        const response = await fetch('/upload-endpoint', {
          method: 'POST',
          body: formData
        });
    
        if (!response.ok) {
          throw new Error('Upload failed');
        }
    
        const result = await response.json();
        console.log('Success:', result);
        alert('Image uploaded successfully!');
      } catch (error) {
        console.error('Error:', error);
        alert('Upload failed. Check console for details.');
      }
    }
  6. Test locally. Open the HTML file in your browser. Select an image, see the preview, and click the button. The request will fail if you don’t have a server endpoint, but you should see the error in the console.
  7. Connect to a real backend. Replace '/upload-endpoint' with the actual URL of your server’s upload route. Make sure your server is configured to accept POST requests with multipart/form-data.

Common Mistakes

  • Forgetting to set the input’s name attribute. When using FormData, the key you append (e.g., ‘image’) must match what your server expects. If your server expects ‘file’, use formData.append('file', file).
  • Not checking file type. Users can select any file type if you don’t filter with accept="image/*" or validate in JavaScript. Always validate on the client side, but remember to validate on the server too—client-side checks are not secure.
  • Using the file path instead of the file object. The input.files[0] is a File object, not a string path. You cannot send a path; you must send the File object itself.
  • Not handling CORS errors. If your frontend and backend are on different domains, you’ll need CORS headers on the server. Otherwise, the browser will block the request.

Tips

  • Use URL.revokeObjectURL() to free memory after the preview is no longer needed (e.g., after upload or when a new file is selected).
  • Add a loading indicator during the upload to give feedback. Disable the button and show a spinner.
  • Validate file size on the client side to avoid uploading huge files that may fail. For example, reject files over 5MB.
  • Use async/await for cleaner code, but be sure to wrap in try/catch to handle errors.
  • Consider using XMLHttpRequest if you need to support older browsers, but for modern browsers, Fetch is simpler.

Troubleshooting

  • Preview not showing: Check that the file input has the correct id and that the event listener is attached after the DOM is loaded. Also, ensure the file is an image (check the console for errors).
  • Upload fails with 404: Your endpoint URL is wrong or the server route doesn’t exist. Double-check the path and that your server is running.
  • Upload fails with 413 (Payload Too Large): The file is too large for the server’s limit. Increase the server’s upload size limit or add client-side size validation.
  • CORS error in console: Your server needs to include the header Access-Control-Allow-Origin with the appropriate origin (or ‘*’). This is a server-side fix.
  • FormData appears empty: Make sure you are appending the file correctly, and that the input still contains the file (don’t clear the input before uploading).

Frequently Asked Questions

Can I upload multiple images at once?

Yes, add the multiple attribute to the input, then loop through input.files and append each file to FormData with the same key (e.g., formData.append('images', file)).

How do I upload an image without a page refresh?

That’s exactly what this guide does—using JavaScript’s Fetch API to send the file asynchronously. The page doesn’t reload because the form submission is prevented (or you don’t use a form at all).

What is the best way to compress an image before uploading?

You can use the Canvas API to resize or compress the image client-side. Draw the image to a canvas, then use canvas.toBlob() to get a compressed Blob and upload that instead of the original file.

Is it safe to rely on client-side file type validation?

No. Client-side validation is only for user experience. Always validate file type and size on the server as well, because malicious users can bypass client-side checks.

Can I upload images using jQuery?

Yes, but it’s not necessary. You can use $.ajax() with FormData, but the native Fetch API is simpler and doesn’t require a library.

How do I show upload progress?

Fetch doesn’t provide progress events. Use XMLHttpRequest instead, which has an upload.onprogress event that gives you the loaded and total bytes.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →