reference
TypeThe reference
field allows a "parent" document to connect to another document in different collection. This relationship only needs to be defined on one side.
Once defined, the values of the referenced document become available to the parent.
Note:reference
withlist: true
is not currently supported. Object type lists can be used as a wrapper aroundreference
field types to create a list of references.
type ReferenceField = {label: stringname: stringtype: 'reference'// The `name` of another collectioncollections: string[]// See https://tina.io/docs/extending-tina/overview/ for customizing the UIui?: {label?: stringdescription?: stringcomponent?: FC<any> | string | nullparse?: (value: string, name: string, field: F) => anyformat?: (value: string, name: string, field: F) => anyvalidate?(value: string,allValues: any,meta: any,field: UIField<F, Shape>): string | undefined | void}}
Given the following schema:
export default defineConfig({//...schema: {collections: [{label: 'Post',name: 'post',path: 'posts',fields: [{label: 'Author',name: 'author',type: 'reference',collections: ['author'],},],},{label: 'Author',name: 'author',path: 'authors',fields: [{label: 'Name',name: 'name',type: 'string',},{label: 'Avatar',name: 'avatar',type: 'string',},],},],},})
The post
collection has a reference
field to the author
collection.
When editing in Tina, the user will be able to choose a document in the author
collection for the value of author
.
When querying for a post
document, the author
key in the response will contain the values of the referenced author
document:
{post(relativePath: "myBlogPost.md") {titleauthor {... on Author {nameavatar}}}}
{type: 'reference',name: 'author',label: 'Author'collections: ['author']}
Figure: File name will be displayed in the reference field selector.
You can search your reference with reference selector.
Note: This search functionality only works based on the file path of the document.
{label: 'Authors',name: 'author',path: 'content/author',format: 'md',fields: [{type: 'string',label: 'Name',name: 'name',required: true,},],}
If you have a long list of reference items, you can filter them in the schema using the ui.collectionFilter
field using a property from the referenced collection.
The current collectionFilter
only supports properties of type string and is also case sensitive ( e.g. Using the example below, if you enter australia
, it will not filter authors by Australia
).
Scenario: You have a list of authors in different locations, and you only want the reference selected in your post collection to be authors from a specific location.
const referenceField = {label: 'Author',name: 'author',type: 'reference',ui: {collectionFilter: {author: {location: 'Australia'}},},collections: ['author'],}
It's also possible to filter references options based on a list of values.
const referenceField = {label: 'Author',name: 'author',type: 'reference',ui: {collectionFilter: {author: {location: ['Australia','United States']}},},collections: ['author'],}
Reference fields on multiple collections can be filtered by the values in either collection.
const referenceField = {label: 'Author & Post',name: 'author and post',type: 'reference',ui: {collectionFilter: {author: {location: ['Australia','United States']},post: {status: 'published',},},},collections: ['author', 'post'],}
The collectionFilter
also support function input, when you need it for dynamic rendering. The input function will trigger during run time.
// Dynamic reference list - You can define as a function here if you need dynamic list but need to make sure the return type match the schemaconst getLocation = () => {const url = new URL('https://bob-northwind-sydney.com')const hostname = url.hostnamereturn hostname};const referenceField = {label: 'Author & Post',name: 'author and post',type: 'reference',ui: {collectionFilter: () => {const location = getLocation();return {author : {location : location}}},},collections: ['author'],}
Note : If you pass as function, the functions need to be passed as executables, not references. The below example will not works.
const referenceField = {label: 'Author & Post',name: 'author and post',type: 'reference',ui: {collectionFilter: () => {return {author : {location : () => {const url = new URL('https://bob-northwind-sydney.com')const hostname = url.hostnamereturn hostname};}}},},collections: ['author'],}
The default reference selector displays the file path, there are cases where you may want to customize what is displayed in the dropdown to provide a better user experience. For example, showing the author's name instead of the file name can make the selection process more intuitive.
Below are some examples on how to customize the reference select using ui.optionComponent
.
Check out custom field to lean more about ui
.
The below example shows a page collection with an author collection as it's reference field. The reference field
has been extract into a module.
{label: 'Page Content',name: 'page',path: 'content/page',format: 'mdx',fields: [referenceField,],},
{label: 'Authors',name: 'author',path: 'content/author',format: 'md',fields: [{type: 'string',label: 'Name',name: 'name',required: true,},{type: 'string',label: 'description',name: 'description',required: true,},],},
const referenceField = {label: 'Author',name: 'author',type: 'reference',ui: {optionComponent: (props: CollectionProps, _internalSys: InternalSys) => {switch (props._collection) {case COLLECTIONS.AUTHOR:return (<AuthorCollectionCustomReferencename={props.name}description={props.description}/>)case COLLECTIONS.POST:return <PostCollectionCustomReference title={props.title} />default:return _internalSys.path}},},collections: ['author', 'post'],}
The Author collection and Post collection are used as a reference for the Page collection. The optionComponent
function allows you to create a custom reference display by providing two parameters: props
and _internalSys
.
props
represents the fields from the reference collection (In this case, the fields from the Author collection, which are name
and description
)._internalSys
contains various useful information for you to use in the custom component such as the file name
and path
.AuthorCollectionCustomReference
and PostCollectionCustomReference
are the custom components that display in the reference select dropdown (see the image below for a visual of the custom reference UI).Tips: You can do console log(props) or console log(_internalSys) in the optionComponent to find out all the provided properties used in your custom component.
The recommended implementation for custom reference selection with type safety.
// You should define the types for the fields in the author collection for type safetyexport interface AuthorProps {name: stringdescription: string_collection: 'author'}// You should define the types for the fields in the post collection for type safetyexport interface PostProps {title: stringexcerpt: string_collection: 'post'}// You should define the list of collection used in the reference for type safetyexport enum COLLECTIONS {AUTHOR = 'author',POST = 'post',}// InternalSys is from tinacms where it gives a lot of useful information for user to customize their custom componentexport interface InternalSys {filename: stringpath: string}export type CollectionProps = AuthorProps | PostProps
You can enforce type safety in your custom reference selection, reducing the likelihood of errors and ensuring consistency across your application.
Using the AuthorProps
interface (you can named it how you like) as an example, the name and description fields are predefined in the Author collection schema and will be passed to the optionComponent
function. The _collection
field is provided by the system to represent the specific collection (author in this case).
Last Edited: October 3, 2024
© TinaCMS 2019–2024