Cover
Gatsby

How to add a file upload to your Gatsby site with TinaCMS

Introduction
How to add a file upload to your Gatsby site with TinaCMS

Hi there! Let's add a file upload field to your Gatsby site. I am going to use TinaCMS for this, in case you don't know it, check out my review:

TinaCMS: probably the best way to edit your Gatsby site in 2020
A colleague recently pointed me on TinaCMS [https://tinacms.org/] and I was interested immediately. I was looking for a solution to develop my own theme with and I already decided GatsbyJS [/exploring-tinacms/gatsbyjs.org/plugins/] would be the way to go. TinaCMS seemed like a perfect match. Build…

Sneak peak

Prerequisites

I assume you are already familiar with Gatsby and you already have a basic project set up and running and you should already have TinaCMS installed. I've set up a simple page with markdown that looks like this:

---
title: Home
slug: /
---
# Home

Hey there!

Now we want to add a file property to the frontMatter (the part at the top).

Prepare the forms

TinaCMS needs forms to create and edit your pages. To provide full functionality we will need two forms: one to create new pages and one to edit existing pages.

At least each form needs some fields. Each field is basically an object describing it's properties. To edit our title we create a form like this:

const editForm = {
	{
      name: 'frontmatter.title',
      component: 'text',
      label: 'Title',
    }
}

This simply takes the text component, gives it a label and saves the value to your frontmatter (the head of your markdown file) as a title.

Let's add the slug.

const editForm = {
	{
      name: 'frontmatter.title',
      component: 'text',
      label: 'Title',
    },
    {
      name: 'frontmatter.slug',
      component: 'text',
      label: 'Slug',
    }
}

That's super easy. Now how can we add a file upload? To be honest this is a little more complex, as you may probably want to add drag and drop feature, you have to add the new file to git and you must save it's path. Luckily I already created a package for this. In fact I've created a whole field collection and a file field is one of them.

mmintel/tinacms-fields
Third-party fields for TinaCMS. Contribute to mmintel/tinacms-fields development by creating an account on GitHub.

Install the file field

We are going to install tinacms-file-field from tinacms-fields. To do so, open your terminal and type:

npm install --save tinacms-file-field

Now create a file called gatsby-browser.js in the root of your project if you don't already have it. And add:

import TinaCMSFileField from 'tinacms-file-field';
import usePages from './src/hooks/use-pages';

export const onClientEntry = () => {
  const fileField = new TinaCMSFileField(window.tinacms);
  fileField.install();
};

This will import the field and install it into Gatsby's onClientEntry hook which is not fired server side. tinacms registers itself into window so we are going to pass this to our field.

Use the field

To use the field you can add it to our existing fields:

const editForm = {
	{
      name: 'frontmatter.title',
      component: 'text',
      label: 'Title',
    },
    {
      name: 'frontmatter.slug',
      component: 'text',
      label: 'Slug',
    },
    {
      name: 'frontmatter.file',
      component: 'file',
      label: 'File',
    },
}

and you are done! Well, there is more to it but this basically already works and will save the upload right next to your page.

Tweaking our field

The field provides some options to get a little more fine grained control.

Change the upload directory

You probably don't want to upload the file next to your page, maybe you have a dedicated folder for uploads. You can use that one of course. To change it, the file field provides two methods: parse and uploadDir. parse set's the path in your markdown file and uploadDir defines where the file is saved.

{
  name: 'frontmatter.file',
  component: 'file',
  description: 'This is a pdf upload field',
  label: 'PDF',
  parse: (file) => `../uploads/${file}`,
  uploadDir: () => 'src/uploads',
},

Allow only specific file types

Let's say you only want to allow the upload of PDF files, you can do it via passing the MIME type as the accept property. If you want to allow only PDFs this would be application/pdf, if you want to allow all image types you can use image/*.

{
  name: 'frontmatter.file',
  component: 'file',
  description: 'This is a pdf upload field',
  label: 'PDF',
  accept: 'application/pdf',
},

Disallow deleting a file

If you added a file and you don't want the editor to remove it, you can toggle the clearable option:

{
  name: 'frontmatter.file',
  component: 'file',
  description: 'This is a pdf upload field',
  label: 'PDF',
  clearable: false
},
Marc Mintel
Author

Marc Mintel

Marc Mintel is a self taught JavaScript and Frontend Developer with heavy focus on React and Vue.

View Comments
Next Post

5 reasons you should abandon default exports

Previous Post

Introducing: tinacms-fields

Success! Your membership now is active.