After modelling our content, and using Tina's API for data-fetching, we can add TinaCMS to our site's frontend and add contextual editing.
To make data editable live on your site, you'll need to set up the TinaCMS context. The default import from tinacms
is a context provider which sets up everything for you. You'll notice we're using a render prop pattern to pass livePageProps
into your component.
// pages/_app.js
import TinaCMS from 'tinacms'
const App = ({ Component, pageProps }) => {
return (
<TinaCMS
/**
* The URL for the content API.
*
* When working locally, this should be http://localhost:4001/graphql.
*
* For Tina Cloud, use https://content.tinajs.io/content/my-client-id/github/my-branch
*/
apiURL="http://localhost:4001/graphql"
>
<Component {...pageProps} />
</TinaCMS>
)
}
export default App
TinaEditProvider
We can leverage Next.js dynamic
imports to avoid bundling TinaCMS with your production build:
// pages/_app.js
import dynamic from 'next/dynamic'
import { TinaEditProvider } from 'tinacms/dist/edit-state'
const TinaCMS = dynamic(() => import('tinacms'), { ssr: false })
const App = ({ Component, pageProps }) => {
return (
<>
<TinaEditProvider
editMode={
<TinaCMS apiURL="http://localhost:4001/graphql">
<Component {...pageProps} />
</TinaCMS>
}
>
<Component {...pageProps} />
</TinaEditProvider>
</>
)
}
export default App
Instead of having the full tinacms
code in your production site, your main production bundle will just contain the much smaller tinacms/dist/edit-state
bundle (>2kb).
You can log into edit mode by visiting /admin
and log out of edit mode by visiting /admin/logout
.
If you setup Tina with
tinacms init
, this should already be setup for you in the/pages/admin/[[...tina]].js
page.
If you do not have a /pages/admin/[[...tina]].js
file, you can create it very easily with two lines:
import { TinaAdmin } from 'tinacms';
export default TinaAdmin;
Contextual editing can be setup on a page with the useTina
hook
// ...
import { useTina } from 'tinacms/dist/edit-state'
const query = `{
getPageDocument(relativePath: "home.mdx"){
data{
body
}
}
}`
export default function Home(props) {
// Pass our data through the "useTina" hook to make it editable
const { data } = useTina({
query,
variables: {},
data: props.data,
})
// Note how our page body uses "data", and not the original "props.data".
// This ensures that the content will be updated in edit-mode as the user types
return <h1>{data.getPageDocument.data.body}</h1>
}
export const getStaticProps = async () => {
const data = await staticRequest({
query,
variables = {},
})
// return the original data, which is used in our production page
return { props: { data } }
}
useTina
hook:useTina
is used to make a piece of Tina content contextually editable. It is code-split, so that in production, this hook will simply pass through its data value. In edit-mode, it registers an editable form in the sidebar, and contextually updates its value as the user types.
useTina
takes in a parameter with a few keys:
query
and variables
: These are the same values that you would use for the backend data-fetching.data
: This is the production value that gets passed through to the response unchanged in production.<TinaCMS>
component.<TinaEditProvider>
component should be used to dynamically code-split Tina out of your production site./admin
route. This page allows editors to log in and enter edit-mode.useTina
hook. In production, it returns the original data unchanged. In edit-mode, it returns the live data, which is updated as the user types in the sidebar.