Media in Tina refers to a set of APIs to allow packages to interact with a central store of files.

Media Store

A Media Store handles media files for the CMS. Media Stores provide a set of functions to specify how media should be sourced, deleted, and saved, among other things.

Supported Media Stores

  • GithubMediaStore: Saves and sources media to/from your Git repository through the GitHub API.
  • NextGithubMediaStore: Configures media sourced from GitHub specifically for Next.js projects.
  • StrapiMediaStore: Handles media stored in a Strapi instance.
  • GitMediaStore: Saves media to your Git repository by writing to the local system and commiting directly.

Creating a Media Store

While there are a few media stores provided by Tina packages, you can create your own media store by implementing the MediaStore interface:

interface MediaStore {
  accept: string
  persist(files: MediaUploadOptions[]): Promise<Media[]>
  previewSrc(
    src: string,
    fieldPath?: string,
    formValues?: any
  ): Promise<string> | string
  list(options?: MediaListOptions): Promise<MediaList>
  delete(media: Media): Promise<void>
}

interface Media {
  type: 'file' | 'dir'
  id: string
  directory: string
  filename: string
  previewSrc?: string
}

interface MediaList {
  items: Media[]
  nextOffset?: string | number
}

interface MediaUploadOptions {
  directory: string
  file: File
}

interface MediaListOptions {
  directory?: string
  limit?: number
  offset?: string | number
}

Media Store

KeyDescription
acceptThe input accept string that describes what kind of files the Media Store will accept.
persistUploads a set of files to the Media Store and returns a Promise containing the Media objects for those files.
previewSrcGiven a src string, it returns a url for previewing that content. This is helpful in cases where the file may not be available in production yet.
listReturns a list of media objects from the media provider. Used in the media manager.
deleteDeletes a media object from the store.

Media

This represents an individual file in the MediaStore.

KeyDescription
typeIndicates whether the object represents a file or a directory.
idA unique identifier for the media item.
directoryThe path to the file in the store. e.g. public/images
filenameThe name of the file. e.g.boat.jpg
previewSrcOptional: A url that provides an image preview of the file.

Media List

This represents a paginated query to the MediaStore and its results.

KeyDescription
itemsAn array of Media objects.
nextOffsetOptional: A key representing the beginning of the next set of records. This will be fed back into your list function if the user requests more records from the media library UI.

Media Upload Options

KeyDescription
directoryThe directory where the file should be uploaded.
fileThe File to be uploaded.

Media List Options

KeyDescription
directoryOptional: The current directory to list media from.
limitOptional: The number of records that should be returned.
offsetOptional: A key representing how far into the list the store should begin returning records from.

Adding a Media Store

Add the media store by assigning it to cms.media.store in a context where you have access to the CMS object.

import { MyMediaStore } from './my-media-store'

cms.media.store = new MyMediaStore()

Or you can define it in the CMS config object:

import { TinaCMS } from 'tinacms'
import { MyMediaStore } from './my-media-store'

const cms = new TinaCMS({
  media: new MyMediaStore(),
})

Extending a Media Store

There may be times when you want to adjust or customize the functionality of a particular media store. For example, with GitMediaStore, you may want to override the previewSrc function to specify exactly how the image previews in the media manager list should be sourced.

Override a method on an extended media store

import { GitMediaStore } from '@tinacms/git-client'

export class MyGitMediaStore extends GitMediaStore {
  previewSrc(src) {
    return /jpg|jpeg|png|svg|gif$/.test(src.toLowerCase())
      ? src.replace('/public', '')
      : null
  }
}

Add the new media store to your app

const client = new GitClient('http://localhost:3000/___tina')

this.cms = new TinaCMS({
  enabled: process.env.NODE_ENV !== 'production',
  toolbar: true,
  sidebar: {
    position: 'overlay',
  },
  apis: {
    git: client,
  },
  media: new MyGitMediaStore(client),
  mediaOptions: {
    // Optional. Configure how many records to retrieve at a time.
    // Passed into a Media Store's *list* function as the *limit*.
    pageSize: 17
  }
})

This is exactly how the NextGithubMediaStore works — it extends GithubMediaStore to customize the functions specifically for Next.js project configuration.

Media Manager

tinacms-media-manager

The media manager is an interface for interacting with a media store. It lists all the available files and directories in the store.

Using the Media Manager

The media manager is opened when a user clicks on an image field. It is also registered as a screen plugin and can be accessed via the global menu. When entering the media manager from an image field, editors can select or upload an image to insert into the field. When entering from the global menu, editors can delete media files.

Programmatic Access

If needed, you can open the media manager by calling cms.media.open:

import { useCMS } from 'tinacms'

const OpenMediaManagerButton = () => {
  const cms = useCMS()
  return (
    <button
      type="button"
      onClick={() => {
        cms.media.open()
      }}
    >
      Open Media Manager
    </button>
  )
}

You can optionally specify a directory that the media manager will open to, as well as an onSelect function that can do something with a media object when the user clicks the Insert button (an Insert button will not appear next to eligible media items when an onSelect function is not specified.)

cms.media.open({
  directory: '/uploads',
  onSelect: media => {
    console.log(`Selected ${media.id}`)
  },
})

Last Edited: June 22, 2021