In this article, I will show you how to integrate Uppy, a popular open-sourced JavaScript uploader, with ColdFusion to allow your users to upload files.

I will show you how to configure and customize Uppy and provide a working example of how to post files to the server using XHR and a ColdFusion backend.

Additionally, we will cover how to change Uppy’s appearance and potentially how to integrate Uppy with Kendo Core themes.



Working Example

Click on the button below to see Uppy in action.

This example posts the files to a back-end ColdFusion endpoint that is running the same code that we covered in our previous Uploading Fies with ColdFusion article.

The code for this working example is at the end of the page.


What is Uppy?

Uppy is an elegant and extensible JavaScript open-source library that can be used to upload files from a variety of different sources. Uppy Core supports image drag and drop, browsing and selecting local images, or simply capturing images from your computer camera.

With the open-source Companion plugin, you can also upload files from BoxDropboxFacebookGoogle DriveInstagramOneDriveUnsplashImport from URL, or Zoom.

 Uppy can be used to upload multiple files and has resumable downloads in case there is a hiccup somewhere.  You can integrate Uppy with other stacks, such as React, Vue, and Angular. Uppy has other advanced functionality for example, it can be used to edit images and generate thumbnails. 

Uppy has a variety of different uploaders available. It supports XHR if you're able to build a custom back-end as we have done here, supports Amazon Web Services with AWS S3, and supports the subscription-based transloadit service.


Integrating Uppy Into a Webpage

Integrating Uppy into a web page is very simple. The hardest part about getting Uppy up and running is trying to locate the required Uppy files.

In this working example, I simply downloaded Uppy and added the uppy.min.js and uppy.min.css files from CDJns and placed them into the head section of the webpage.

Uppy also can be installed using popular package managers with NPM and Yarn as well as using CDN. See https://uppy.io/docs/uppy/#install for more information. 

If you don't want to muck around with a bunch of import scripts and package managers, you can simply head over to https://cdnjs.com/libraries/uppy or https://www.jsdelivr.com/package/npm/uppy, and include the assets via CDN.


Uppy File Restrictions

Uppy has several file restriction properties that can be used to restrict the available files from the user.

Commonly used properties are:

  • maxFileSize
  • minFileSize
  • maxTotalFileSize
  • maxNumberOfFiles
  • allowedFileTypes

The file sizes are measured in bytes. If you want to limit the size to 150KB use 1024* 150.

Typically the following formula is used to set these properties:


maxFileSize: 1024 *150 (150KB)

allowedFileTypes Property

The allowedFileTypes property is an array of strings that can contain wildcards, file extensions, or mime types.

For example, all of the following will work to restrict the files to images:

Wildcards:


allowedFileTypes: ['image/*'] // other popular wildcards are "video/*"

File Extensions:


allowedFileTypes: [".jpg", ".jpeg", ".png", ".gif", ".webp"],

Mime Types:


allowedFileTypes: ["image/jpeg", "image/x-png", "image/gif", "image/webp"],

A Word of Caution When Using Uppy File Restrictions!

Uppy restricts the files using the accept attribute that is used by the browser. The browser uses these restrictions and provides hints to the operating system to display the proper files. However, there are ways to override these suggestions and accept another file. Neither Uppy, nor the client browser, provides validation and it is essential to provide validation on the server.


Uppy Dashboard API

The Uppy dashboard arguments control the appearance and functionality of the main Uppy dashboard.

theme (default light)

There are two built-in themes, dark and light. The available arguments are light, dark, and auto. I have noticed that auto sometimes does not work as expected and always specify the theme to match my background.

You can always change the CSS if you want to further modify the dashboard appearance, see Theming Uppy at the end of this article


inline (default false)

Inline is a boolean argument and will render the Dashboard in either inline mode when set to true, or modal mode when set to false.

I set inline true to have more control and render multiple Uppy dialogs on a given page. When the Dashboard is set inline, each Uppy instance will be rendered inside of the element specified in the target argument, see below.


target (default body)

When specified, target will cause the Uppy Dashboard to be rendered inside the specified element.

In Galaxie Blog (the engine for the blog that you are looking at), I use multiple Uppy instances to Uppy, each using unique targets. This allows me to configure each Uppy instance to handle different things, such as uploading fonts, images, videos, etc. If you don't specify a target, Uppy will be in modal mode only allowing for one instance.


.use(Uppy.Dashboard, {
	theme: 'dark',
	inline: true,
	target: '#uppyExample',
	// We are using formData in order to pass additonal arguments from the form
	formData: true,
	proudlyDisplayPoweredByUppy: false,
})

XHR Upload Arguments

Using Uppy's XHR uploader allows you to use your own self-hosted back-end. In this example, I am using the following arguments:


formData (default true)

When set to true, additional metadata can be passed to the service endpoint.


fieldName (default files[])

This optional setting allows you to set the form name that is used to send files to the remote service. This can only be used if you don't have the bundled argument enabled.

I changed the default form name in my code as ColdFusion will throw an error if the file.fileField is specified on the backend.

See https://www.gregoryalexander.com/blog/2024/2/18/uploading-files-with-coldfusion#mcetoc_1hmvg688ike for more information.


endpoint (required)

The URL of the service endpoint. This argument is required.

When using ColdFusion, it is best if this is posted to a ColdFusion component with an upload method.

See https://www.gregoryalexander.com/blog/2024/2/18/uploading-files-with-coldfusion#mcetoc_1hmvg688ikh to get the code. 

If you're using PHP, there is a short how-to article found at https://uppy.io/docs/xhr-upload/#how-to-upload-to-a-php-server.


.use(Uppy.XHRUpload, { 
	// We are using formData in order to pass additonal arguments from the form
	formData: true,
	// Change the name of the form to files instead of the default 'files[]'
	fieldName: 'files',
	endpoint: '<cfoutput>#application.baseUrl#</cfoutput>/demo/fileUpload/FileUpload.cfc?method=uploadImage&mediaProcessType=uppyExample' 
})

Common Uppy Events

Uppy exposes a handful of events. Some of the commonly used events are:


upload-success

Fired when the file upload is completed on the server. This event is often used to display messages sent back from the server.

In our example, I am either displaying the error or the file location that is sent back as a JSON response from the server:


on('upload-success', (file, response) => {
	// The server is returning the error and location inside a JSON object.
	// Display the error message if available
	if (response.body.errorMessage){
		alert("Error: " + response.body.errorMessage);
	} else {
		alert("Your image has been saved at: https://www.gregoryalexander.com" + response.body.location);// The full path of the file that was just uploaded to the server
	}
 })

To understand how the URL is set and returned from the server, search for the imageUrl in our previous Uploading Files With ColdFusion article.


Custom Event Fired When the 'My Device' Icon is Clicked

Uppy does not expose an event when Uppy's 'My Device' icon is clicked so I created the following event using jQuery's onClick event. I typically use this event to raise a please wait window that is closed when the file(s) have been added to the Uppy dashboard.


// Note: there is no event when the dashboard the 'My Device' icon is clicked. This is a workaround. We are going to use jQuery's on-click event and put in the class of the button. This is required as the Uppy button does not have an ID.
	$(".uppy-Dashboard-input").on('click', function(event){
});

file-added

Fired when a file has been added to the Uppy dashboard.


uppy.on('file-added', (file) => {
	// Do nothing (for now)
})

upload

The upload event is fired when the upload button is clicked.


// 3) When the upload button was pressed
uppy.on('upload', (data) => {
	// Do nothing (for now)
})

upload-error

Fired when the http response status code from the server indicates a failure. 


// 4) Error handling
uppy.on('upload-error', (file, error, response) => {
	// Do nothing (for now)
})

complete

Raised when everything is complete.


// 5) When the upload is complete to the server
uppy.on('complete', (result) => {
	// Do nothing (for now)
})

See https://uppy.io/docs/uppy/#events for the full list of Uppy events.


ColdFusion Server Endpoint

The backend server endpoint has been covered in our previous Uploading Files With ColdFusion article. The Uppy Github site has more documentation on how to implement it with other languages.


Theming Uppy

Uppy's uppy.min.css file can be modified to change the appearance of the Uppy UI. I have modified this file to match Uppy with Kendo UI and Kendo Core themes.

If you are interested in using Kendo (or Kendo Core) with Uppy, I have created an optional separate CSS file that can be used to match Uppy with the Kendo-related themes. This CSS file uses the getPrimaryColorsByTheme ColdFusion template to change the appearance of the Uppy UI controls to make them consistent with the Kendo themes. 

The getPrimaryColorsByTheme template is well documented, and I have isolated the key CSS classes in Uppy where I have inserted ColdFusion code. The logic should be easily reproducible if you're using another server-side language. If you want to make your Uppy theme, search the included file for '<cfouptut>' and change the primary colors as you see fit.

Click on the button below to view the custom CSS file.


Uppy Configuration Code

The working example uses the following code:


<!doctype html>
<html lang="en">
  <head>
	<title></title>
	<meta charset="UTF-8" />
	<script src="/blog/common/libs/uppy/uppy.min.js"></script>
	<link rel="stylesheet" href="/blog/common/libs/uppy/uppy.min.css">

  </head>
  <body>

	<div id="uppyExample"></div>
	<script>
		var uppy = Uppy.Core({
			restrictions: {
				maxNumberOfFiles: 12,  // limit 12 images
				allowedFileTypes: ['image/*'], // only allow images
				maxFileSize: 1024*150 //150 KB
			}
		})

		.use(Uppy.Dashboard, {
			theme: 'dark',
			inline: true,
			target: '#uppyExample',
			// We are using formData in order to pass additonal arguments from the form
			formData: true,
			proudlyDisplayPoweredByUppy: false,
		})

		// Allow users to take pictures via the onboard camera
		.use(Uppy.Webcam, { target: Uppy.Dashboard })
		// Use the built in image editor
		.use(Uppy.ImageEditor, { 
			target: Uppy.Dashboard,
			quality: 0.8 // for the resulting image, 0.8 is a sensible default
		})

		// This is used for debugging purposes and can be removed in production
		uppy.on('file-added', (file) => {
			// Do nothing (for now)
		})

		// Use XHR and send the media to the server for processing. The selectorId ColdFusion var will either be gallery or carousel
		.use(Uppy.XHRUpload, { 
			// Change the name of the form to files instead of the default 'files[]'
			fieldName: 'files',
			endpoint: '<cfoutput>#application.baseUrl#</cfoutput>/demo/fileUpload/FileUpload.cfc?method=uploadImage&mediaProcessType=uppyExample' 
		})
		.on('upload-success', (file, response) => {
			// The server is returning the error and location inside a JSON object.
			// Display the error message if available
			if (response.body.errorMessage){
				alert("Error: " + response.body.errorMessage);
			} else {
				alert("Your image has been saved at: https://www.gregoryalexander.com" + response.body.location);// The full path of the file that was just uploaded to the server
			}
		})

	</script>

  </body>
</html>

Further Reading: