While this tutorial has content that we believe is of great benefit to our community, we have not yet tested or edited it to ensure you have an error-free learning experience. It's on our list, and we're working on it! You can help us out by using the "report an issue" button at the bottom of the tutorial.

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.

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.

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) .

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);

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. 🤞