We can customize the component templates used by FilePond to render the user interface.
The createFilePondEntryList function returns the default template used by FilePond to render the user interface.
Templating Basics
The template returned by createFilePondEntryList() is a JavaScript object tree that describes the user interface.
Objects in the tree are of type TemplateNode, these are either an ElementNode, ComponentNode, or SwitchNode.
ElementNode
An ElementNode describes an element, for example:
{
tag: 'button',
attrs: {
type: 'button',
onclick: () => {
console.log('Hello World!');
}
},
children: 'Click me!'
}
ComponentNode
An ComponentNode describes a Svelte component, for example:
{
component: 'TextInput',
props: {
type: 'email',
oninput: (detail) => {
console.log('Hello World!',detail);
}
}
}
SwitchNode
A switch node allows choosing different render paths depending on context data.
{
if: {
test: ({ entry }) => !!entry.file,
then: {
tag: 'span',
children: 'Is file '
}
},
else: {
tag: 'span',
children: 'Is not a file'
}
}
Included presets
These are helper functions that append a rich component to the template.
Image view
We can use the appendEntryImageView helper function to add an image preview. This will show a preview of added images.
import { defineFilePond } from 'filepond';
import { locale } from 'filepond/locales/en-gb.js';
import { createFilePondEntryList, appendEntryImageView } from 'filepond/templates';
// Add image view to default template
const template = createFilePondEntryList();
appendEntryImageView(template, {
// Image view options
});
defineFilePond({
locale,
// Set custom template
EntryListView: {
template,
},
});
Video view
We can use the appendEntryVideoView helper function to add a video preview. This will show a video player when videos are added that are supported by the browser.
import { defineFilePond } from 'filepond';
import { locale } from 'filepond/locales/en-gb.js';
import { createFilePondEntryList, appendEntryImageView } from 'filepond/templates';
// Add video view to default template
const template = createFilePondEntryList();
appendEntryVideoView(template, {
// Video view options
});
defineFilePond({
locale,
// Set custom template
EntryListView: {
template,
},
});
Example use cases
Handle click on a file
In this example we add a click event listener to the entry item name, when clicked the browser will download the file.
We import and use the withNodeTree helper function to make it easier to modify the default FilePond template returned by createFilePondEntryList.
To prepare the download link we use the ObjectURLView which automatically creates an ObjectURL for each file which we can then use in our link.
<form action="/upload" method="POST">
<label for="my-file">Document</label>
<file-pond>
<input id="my-file" type="file" name="files" multiple required />
</file-pond>
<button type="submit">Upload</button>
</form>
<style>
file-pond::part(download-link) {
color: currentColor;
pointer-events: all;
}
</style>
<script type="module">
import { defineFilePond } from 'filepond';
import { locale } from 'filepond/locales/en-gb.js';
import { ObjectURLView } from 'filepond/extensions/object-url-view.js';
import { withNodeTree, createFilePondEntryList } from 'filepond/templates';
// Create the default template
const template = createFilePondEntryList();
// Replace the file-info-main component with an anchor when we have an ObjectURL
withNodeTree(template).update('file-info-main', (node) => {
node.children = {
// When we have our ObjectURL we render an anchor
if: {
test: ({ entry }) => !!entry.extension.ObjectURLView?.url,
then: {
tag: 'a',
children: '{{entry.name}}',
attrs: ({ entry }) => ({
part: 'download-link',
download: entry.name,
href: entry.extension.ObjectURLView.url,
}),
},
},
// If we don't have an ObjectURL we render a span
else: {
tag: 'span',
children: '{{entry.name}}',
},
};
});
defineFilePond({
locale,
// Load ObjectURLView extension
extensions: [ObjectURLView],
// Set custom template
EntryListView: {
template,
},
});
</script>
While it does create a less visible interaction pattern, we can also add the click listener to the entry item itself.
In this situation, to offer the file as a download, we’ll use the downloadFile function as shown in this article on handling file downloads.
In the example below we don’t need the ObjectURLView extension as we’re creating and revoking the URL when we click the link.
import { defineFilePond } from 'filepond';
import { locale } from 'filepond/locales/en-gb.js';
import { createFilePondEntryList, withNodeTree } from 'filepond/templates';
// Create the default template
const template = createFilePondEntryList();
// Add onclick attribute to the entry component
withNodeTree(template).update('entry', (node) => {
// Backup current props function
const computeEntryPropsWithContext = node.props;
// Set our custom props function
node.props = (context) => ({
// Compute props for context
...computeEntryPropsWithContext(context),
// Add our event handler
onclick: function (e) {
// Ignore controls
if (e.target.nodeName === 'BUTTON') {
return;
}
// Download the file
downloadFile(context.entry.file);
},
});
});
defineFilePond({
locale,
// Set custom template
EntryListView: {
template,
},
});
// Helper function to download files
function downloadFile(file) {
// Create a link and set the URL using `createObjectURL`
const link = document.createElement('a');
link.style.display = 'none';
link.href = URL.createObjectURL(file);
link.download = file.name;
// It needs to be added to the DOM so it can be clicked
document.body.appendChild(link);
link.click();
// To make this work on Firefox we need to wait
// a little while before removing it.
setTimeout(() => {
URL.revokeObjectURL(link.href);
link.parentNode.removeChild(link);
}, 0);
}