Tina Docs
Introduction
Overview
Introduction To TinaCMS
Getting Started
Using the Tina Editor
FAQ
Core Concepts
Content Modeling
Data Fetching
Visual Editing
Querying Content
Overview
Writing custom queries
Editing
Overview
Markdown & MDX
Block-based editing
Single Document Collections
Customizing Tina
Overview
Validation
Custom Field Components
Custom List Rendering
Format and Parse Input
Filename Customization
Before Submit function
Going To Production
Overview
Tina Cloud
Self-Hosted
Drafts
Overview
Draft Fields
Editorial Workflow
Guides
Overview
Framework Guides
Separate Content Repo
Querying Tina Content at Runtime
Internationalization
Migrating From Forestry
Further Reference
Overview
Config
Schema
The "tina" folder
The TinaCMS CLI
Media
Search
Content API
Tina's edit state
The "tinaField" helper
Self-Hosted Components

Content Modeling with TinaCMS


Introduction

The Tina schema defines the shape of your content. Tina uses a "content-modeling as code" approach. This has a few benefits compared to modelling through a UI:

  • The schema is version-controlled
  • Mutating the schema is easy, as you can test out changes locally, or in a branch.
  • The developer can extend the schema in interesting ways (custom validation, custom UI fields, etc).

The content model, and all configuration code is defined in a file called tina/config.{ts,js,tsx}.

// tina/config.{ts,js,tsx}
import { defineConfig } from 'tinacms'
export default defineConfig({
// ...
schema: {
collections: [
{
label: 'Blog Posts',
name: 'post',
path: 'content/posts',
fields: [
{
type: 'string',
label: 'Title',
name: 'title',
},
{
type: 'string',
label: 'Post Body',
name: 'body',
isBody: true,
},
],
},
],
},
})

Defining "collections"

Each item in your collections array represents its own entity. In the above example, we defined a post collection, and set its path as content/posts, which maps to a directory in our site's repository. Each collection contains an array of fields, that each have a defined type.

---
title: This is my title
---
This is my main post body.
Note: The isBody property is used to output a given field to the markdown body, instead of its frontmatter.

Once we've defined a collection, we can edit its fields through the Tina UI, or query its content using the Tina Content API.

"List" fields

Specifying list: true on almost any field type will turn that field into an array of items:

fields: [
{
label: 'Tags',
name: 'tags',
type: 'string',
list: true,
},
]

Live Example...

Caveats

Certain field types cannot be set as a list, or may not have a specific list UI when changed through the content editor. To create lists of these fields, they can be wrapped in an object field type that has been been marked with list: true.

Types that cannot be marked as a list:

A list of these types can be set, but they appear as a singular field in the content editor:

Limiting values to a set of options

Any scalar field can accept an options array, note that in the example below we're using both options and list properties:

// ...
fields: [
{
label: 'Categories',
name: 'categories',
type: 'string',
list: true,
options: [
{
value: 'movies',
label: 'Movies',
},
{
value: 'music',
label: 'Music',
},
],
},
]

See Example

Omitting list: true (or setting it to false) would result in a single-select radio field.

Grouping properties as an "object"

An object type takes either a fields or templates property (just like the collections definition). The simplest kind of object is one with fields:

// ...
fields: [
{
label: 'Testimonial',
name: 'testimonial',
type: 'object',
fields: [
{
label: 'Author',
name: 'author',
type: 'string',
},
{
label: 'Role',
name: 'role',
type: 'string',
},
{
label: 'Quote',
name: 'quote',
type: 'string',
ui: {
component: 'textarea',
},
},
],
},
]
// ...

See Example

Setting list: true would turn the values into an array:

See Example

More complex shapes can be built by using the templates property. This allows your editors to build out pages using predefined blocks.

Defining defaults

Every collection has a defaultItem property, which is used to populate the form when creating a new item. This is useful for setting default values for fields, or for adding default content to the markdown body.

Default item

export default defineConfig({
// ...
schema: {
collections: [
{
label: 'Blog Posts',
name: 'post',
path: 'content/posts',
defaultItem: () => {
return {
// When a new post is created the title field will be set to "New post"
title: 'New Post',
}
},
fields: [
{
type: 'string',
label: 'Title',
name: 'title',
},
],
},
],
},
})

See the docs for more examples of how to define defaults.

Default value for objects

To set default values for objects of fields, use the defaultItem property (see example here).

Default value for rich-text

Currently, when setting a default value for a rich-text field, you must provide the document Abstract Syntax Tree (AST). See the following example:

export default defineConfig({
// ...
schema: {
collections: [
{
label: 'Blog Posts',
name: 'post',
path: 'content/posts',
defaultItem: () => {
return {
title: 'My New Post',
// The body will be populated with "Default Text"
body: {
type: 'root',
children: [
{
type: 'p',
children: [
{
type: 'text',
text: 'Default Text',
},
],
},
],
},
}
},
fields: [
{
type: 'string',
label: 'Title',
name: 'title',
},
{
type: 'string',
label: 'Post Body',
name: 'body',
isBody: true,
},
],
},
],
},
})

Referencing another document

The reference field connects one document to another and only needs to be defined on one side of the relationship. You can specify any number of collections you'd like to connect:

// ...
fields: [
// ...
{
label: 'Author',
name: 'author',
type: 'reference',
collections: ['author'], // points to a collection with the name "author"
},
]
//

See Example

Available data types

Each field in a collection can be of the following type:

scalar types

nonscalar types

Video Tutorial

For those who prefer to learn from video, you can check out a snippet on media from our "TinaCMS Deep Dive" series.

Summary

  • Your content is modeled in the tina/config.{ts,js,tsx} in your repo using defineConfig.
  • Your content model contains an array of "collections". A "collection" maps a content type to a directory in your repo.
  • A "collection" contains multiple fields, which can be of multiple scalar or non-scalar data types.

Last Edited: September 17, 2024

Next
Data Fetching

Product

Showcase
TinaCloud
Introduction
How Tina Works
Roadmap

Resources

Blog
Examples
Support
Media

Whats New
TinaCMS
TinaCloud
Use Cases
Agencies
Documentation
Teams
Jamstack CMS
Benefits
MDX
Markdown
Git
Editorial Workflow
Customization
SEO
Comparisons
TinaCMS vs Storyblok
TinaCMS vs Sanity
TinaCMS vs DecapCMS
TinaCMS vs Contentful
TinaCMS vs Builder.io
TinaCMS vs Strapi
Integrations
Astro
Hugo
NextJS
Jekyll