Announcing the new "Extending Tina"

April 28, 2022

By Logan Anderson

Note: This post is out of date. For the latest Tina usage, see our docs.

The latest update empowers developers to put validation ,component and parse functions directly into the schema.

Quick Demo

Validation

Below, if you click the "pencil" icon and edit the "Title" field, the validation function runs and gives an error to the user when it is more than 20 characters.

Custom components

With this update, you can create your custom components easily; see the example below for using a custom component.

How to update

Check out this getting started guide if you want to get started with tina

To update do the following,

1. Update imports in the .tina/schema.{ts,tsx,js} file

We will be using the schema file on the backend and frontend (previously, it was just the frontend), so all imports from @tinacms/cli need to be changed to tinacms.

2. add defineConfig to the schema

We are now recommending that your config be separate from the wrapper component and placed in the schema.{ts,tsx,js} or in its only folder.

So previously, the schema file would look like this.

export default defineSchema({
// schema here
})

must be changed to

import { defineConfig } from 'tinacms'
export default defineConfig({
// pass schema and apiUrl to the config (required) (this is how it is passed to the fronend)
schema: schema,
apiUrl: apiUrl,
// add other config that would have previosly been in the _app.{js,tsx} file in the <TinaCMS> component.
cmsCallback: (cms) => {
//...
},
mediaStore: async () => {
//...
},
collections: [
// ...
],
})
export default schema

You should add the following two files in the .tina/components folder.

3. Add .tina/components/TinaProvider.js

This file handles the Tina configuration and the tina provider component, and this will only load when in edit mode, and an example below.

import TinaCMS from 'tinacms'
import { tinaConfig } from '../schema.ts'
// Importing the TinaProvider directly into your page will cause Tina to be added to the production bundle.
// Instead, import the tina/provider/index default export to have it dynamically imported in edit-mode
/**
*
* @private Do not import this directly, please import the dynamic provider instead
*/
const TinaProvider = ({ children }) => {
return <TinaCMS {...tinaConfig}>{children}</TinaCMS>
}

4. Add .tina/components/TinaDynamicProvider.js

The TinaDynamicProvider.js handles the loading of the TinaProvider when in "Edit mode." See the provided below

import dynamic from 'next/dynamic'
const TinaProvider = dynamic(() => import('./TinaProvider'), { ssr: false })
import { TinaEditProvider } from 'tinacms/dist/edit-state'
const DynamicTina = ({ children }) => {
return (
<>
<TinaEditProvider editMode={<TinaProvider>{children}</TinaProvider>}>
{children}
</TinaEditProvider>
</>
)
}
export default DynamicTina
Read more about these two files in our reference docs

5. Update your _app.{js,tsx}

The last step is to update your _app.{js,tsx}. Since the config and the provider are in a separate file, this will be less code than what was there previously.

_app.{js,tsx} before:

import dynamic from 'next/dynamic'
import { TinaEditProvider } from 'tinacms/dist/edit-state'
//...
const App = ({ Component, pageProps }) => {
return (
<>
<TinaEditProvider
showEditButton={true}
editMode={
<TinaCMS
cmsCallback={(cms) => {
//...
}}
apiURL={apiURL}
>
<Component {...pageProps} />
</TinaCMS>
}
>
<Component {...pageProps} />
</TinaEditProvider>
</>
)
}
export default App

_app.{js,tsx} after:

import DynamicTina from '../.tina/components/TinaDynamicProvider'
const App = ({ Component, pageProps }) => {
return (
<DynamicTina>
<Component {...pageProps} />
</DynamicTina>
)
}
export default App

This separation of config into another file makes it much cleaner and easier to understand. In addition, the schema now being a part of the config and used on the frontend will allow functions to be passed and used. It will also allow us to make fewer network requests since we have more information.

Closing words

The new features we talked about in this article only scratch the surface of what is possible; please read the docs to find out more.

If you are having any issues at all, please reach out to us on discord or create a github issue.

Last Edited: April 28, 2022