Tutorial

Exploring TinaCMS with Gatsby

Published on January 13, 2020
author

Joshua Hall

Exploring TinaCMS with Gatsby

As much as we can all agree about how awesome markdown is, it will always be significantly more satisfying to see your edits and style changes on your pages in real time. 🦙 TinaCMS, when coupled with Gatsby, gives us to ability to manipulate our markdown files directly on our pages, visually. TinaCMS also works with Next.js, but here we’ll explore this powerful new tool with a Gatsby site.

Installation

We’ll get started with the gatsby-starter-blog starter, since that already has everything we need for markdown posts.

There are only four main things we need, TinaCMS itself, styled-components (which TinaCMS is dependent on), Tina’s remark plugin for handling our markdown, and Tina’s git plugin to give it the ability to directly alter files in our filesystem and make commits to your Github account when you save a post.

$ gatsby new tina-example https://github.com/gatsbyjs/gatsby-starter-blog
$ yarn add gatsby-plugin-tinacms styled-components gatsby-tinacms-remark gatsby-tinacms-git

Setup

The initial setup couldn’t be easier: we’ll add gatsby-plugin-tinacms to gatsby-config.js with the remark and git plugins. I personally prefer to set the position to fixed, since by default the sidebar will push our site to the side.

gatsby-config.js
{
  resolve: 'gatsby-plugin-tinacms',
  options: {
    plugins: [
      "gatsby-tinacms-git",
      "gatsby-tinacms-remark",
    ],
    position: 'fixed'
  }
}

With just that, your page should have a little blue tab on the bottom to open a new sidebar.

Tina Sidebar

Now, in our post template we’ll need to get some extra things from our query; fileRelativePath, rawFrontmatter, rawMarkdownBody. These will be used by the remarkForm higher-order component that TinaCMS gives us, all we have to do is wrap our exported component with it and you should be good to go.

blog-post.js
import { remarkForm } from "gatsby-tinacms-remark";

class BlogPostTemplate extends React.Component { 
    // ...
};

export default remarkForm(BlogPostTemplate);

export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    # ...
    markdownRemark(fields: { slug: { eq: $slug } }) {
      # ...
      fileRelativePath
      rawFrontmatter
      rawMarkdownBody
    }
  }
`;

Now Tina has access to all your markdown posts and will update and quickly reload the page to show any new changes. Plus whenever you hit the save button there will be a small commit made to your Github repo, so any hosting platform connected to it will be updated automatically.

Sidebar Editing

Inline Editing

Having to work with long content entirely in the sidebar would be a pain, and instead we can setup our outputted content as the editor so we can directly interact with our content on the page and keep the sidebar just for metadata, theming, adding/deleting, etc.

Not much even needs to be changed, instead of remarkForm we’ll wrap the page template in a liveRemarkForm and wrap any part we want to be editable with a TinaField. TinaField just needs to be named rawMarkdownBody and passed the Wysiwyg library as a prop. Wysiwyg is short for what you see is what you get, which is what will give us most of the real-time editing capabilities.

We’ll activate the editing mode whenever you click on the article itself, with the handy setIsEditing method.

layout.js
import { liveRemarkForm } from 'gatsby-tinacms-remark';
import { Wysiwyg } from '@tinacms/fields';
import { TinaField } from '@tinacms/form-builder';

const BlogPostTemplate = props => {
  const { previous, next } = props.pageContext;

  return (
    <Layout>
        {*/ ... */}
      <TinaField name="rawMarkdownBody" Component={Wysiwyg}>
        <article onClick={() => props.setIsEditing(true)}>
            {*/ ... */}
        </article>
      </TinaField>
    </Layout>
  )
};

The first prop in the setIsEditing method is the current editing state, so if instead you want to use a toggle button you can do something like props.setIsEditing(editing => !editing).

Inline Editing with TinaCMS

Deleting Posts

Removing files is ridiculously simple, just import the handy DeleteAction method, throw into a an object with a label, and give it to liveRemarkForm.

blog-post.js
import { liveRemarkForm, DeleteAction } from 'gatsby-tinacms-remark';

const deleteButton = {
  label: 'Delete',
  actions: [DeleteAction]
};

export default liveRemarkForm(BlogPostTemplate, deleteButton);

Now next to the save button is a little menu with a Delete option.

Adding Posts

The ability to add posts is where things get a little heavy on the boilerplate.

We’ll use the createRemarkButton function to add a new option to our sidebar. Whatever we return to filename will be added to our filesystem, and we can use the slugify library to format the name for our file.

frontmatter will handle the metadata for our post from our form. fields will establish the form itself. Finally, we’ll use the withPlugin HOC to add our new button to our layout.

layout.js
import { withPlugin } from 'tinacms';
import { createRemarkButton } from 'gatsby-tinacms-remark';
import slugify from 'react-slugify';

const CreatePostButton = createRemarkButton({
  label: "New Post",
  filename(form) {
    let slug = slugify(form.title.toLowerCase())
    return `content/blog/${slug}/${slug}.md`
  },
  frontmatter(form) {
    let slug = slugify(form.title.toLowerCase())
    return new Promise(resolve => {
      resolve({
        title: form.title,
        description: form.description,
        data: new Date(),
        path: `content/blog/${slug}/${slug}`,
      })
    })
  },
  fields: [
    { name: "title", label: "Title", component: "text", required: true },
    { name: "description", label: "Description", component: "text", required: true },
  ],
});

export default withPlugin(Layout, CreatePostButton);

Add a new post using TinaCMS

Conclusion

There is still so much to explore with TinaCMS like creating/deleting pages with JSON and creating custom fields, blocks, and plugins.

Since TinaCMS a still fairly new tech, there’s still many ways it could be improved. They’re currently working on adding team support for different roles and editing permissions. Hopefully in the future they’ll add a way for a non-tech client to access Tina and edit everything on-site. 🤞

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Joshua Hall

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.