Guide

Rich-Text Lanjutan

Diagram Mermaid dan custom template di field rich-text, plus satu gotcha soal parser-nya.

Selain markdown dasar (bold, italic, link, list, blockquote, semuanya otomatis dirender lewat <TinaMarkdown>), nuxt-tina juga support diagram Mermaid di field rich-text.

Diagram Mermaid

Tambahin 'mermaid' ke toolbar field rich-text-nya:

{
  type: 'rich-text',
  name: 'body',
  isBody: true,
  overrides: {
    toolbar: ['heading', 'link', 'bold', 'italic', 'mermaid', 'codeBlock', /* ... */],
  },
}

TinaMarkdown nggak render diagram Mermaid secara default. mermaid itu dependency yang gede, jadi sifatnya opt-in:

npm install mermaid
<TinaMarkdown :content="post.body" :components="{ 'tina-mermaid': TinaMermaid }" />

TinaMermaid udah auto-import sama module-nya, jadi nggak perlu import manual. Kalau prop components-nya udah disambungkan, code block mermaid dirender jadi diagram SVG lewat mermaid.render() (di-import secara dinamis cuma pas diagramnya beneran ke-mount, jadi nggak nambah bundle kalau nggak dipakai). Tanpa prop itu, code block mermaid cuma dirender sebagai kode biasa.

Custom template

Field rich-text bisa punya template sendiri (syntax {{ shortcode }} Tina atau embed ala MDX):

{
  type: 'rich-text',
  name: 'body',
  isBody: true,
  templates: [
    {
      name: 'callout',
      label: 'Callout',
      match: { start: '{{', end: '}}' },
      fields: [
        { name: '_value', type: 'string', label: 'Text', required: true },
      ],
    },
  ],
}

nuxt-tina nggak nyediain komponen buat custom template tertentu: semuanya dirender lewat <TinaMarkdown> sebagai wrapper generic: <div data-tina-type="callout">...</div>. Style atau target-in pakai attribute itu di CSS kamu sendiri. Beda sama Mermaid, sekarang belum ada hook prop components buat nukar custom template tertentu jadi komponen Vue kamu sendiri: nambahin coverage itu masih di roadmap, ditrack di source adapter-nya sendiri (comark-adapter.ts).

⚠️ Gotcha: template nggak keparse kalau format: 'md'

Collection dengan format: 'md' otomatis dapat parser: { type: 'markdown' } di field rich-text-nya, dan mode parser itu sama sekali ngeskip logic template-matching (templates[].match) di dalam @tinacms/mdx. Tanpa override, {{ callout "..." }} cuma jadi teks biasa, bukan node yang keparse.

Fix-nya: override parser field-nya secara eksplisit:

{
  type: 'rich-text',
  name: 'body',
  isBody: true,
  parser: {
    type: 'mdx', // paksa lewat jalur yang beneran preprocess template
  },
  templates: [ /* ... */ ],
}

Ini berlaku buat shortcode custom ({{ }}) maupun embed MDX ala JSX yang beneran (<Cta ... />).

Bentuk custom template di AST

Kalau kamu mau bikin render adapter sendiri, node custom template muncul di AST kayak gini:

{
  "type": "mdxJsxFlowElement",
  "name": "callout",
  "props": { "_value": "Ini contoh callout." },
  "children": [{ "type": "text", "text": "" }]
}

comark-adapter.ts udah nangani shape ini: lihat case mdxJsxFlowElement/mdxJsxTextElement di file itu buat contoh pattern-nya kalau kamu mau extend.

Copyright © 2026