Api

useTina()

Referensi API buat composable useTina().

Composable utama buat konsumsi data TinaCMS dengan update reaktif secara real-time.

Type signature

function useTina<T extends Record<string, unknown>>(
  props: UseTinaOptions<T> | Ref<any> | ComputedRef<any>
): UseTinaReturn<T>

Kamu bisa pass objek options, atau ref langsung, termasuk seluruh ref yang dibalikin useAsyncData/useFetch (lihat contoh di bawah).

Parameter: props (sebagai UseTinaOptions<T>)

PropertiTipeWajibDeskripsi
dataTNggakData awal, dari SSR, panggilan API, atau query Tina.
querystringNggakString query GraphQL Tina, dibutuhkan buat handshake visual-editing.
variablesRecord<string, unknown>NggakVariable GraphQL buat query-nya.

Return value

PropertiTipeDeskripsi
dataRef<T>Data reaktif, otomatis update pas form di Tina Admin berubah.
isEditingRef<boolean>true pas halamannya dibuka di mode editing/preview.
isInIframeRef<boolean>true pas halamannya dimuat di dalam iframe Tina Admin.
quickEditEnabledRef<boolean>true selama mode quick-edit (klik-buat-edit) diaktifin dari Tina Admin.
bridgeErrorRef<Error | null>Error terakhir yang ketangkep pas komunikasi sama Tina Admin, atau null kalau nggak ada yang gagal. Sama-sama dipakai dengan useTinaBridge().
refresh() => Promise<void>Maksa refreshNuxtData(). Dipakai setelah event save yang beneran.

tinaField(object, property?, index?)

Helper yang bikin attribute data-tina-field, jadi Tina Admin tau elemen DOM mana yang representasiin field mana.

<h1 :data-tina-field="tinaField(post, 'title')">{{ post.title }}</h1>

<!-- buat item di dalam list, sertain index-nya -->
<span
  v-for="(tag, idx) in post.tags"
  :key="idx"
  :data-tina-field="tinaField(post, 'tags', idx)"
>{{ tag }}</span>

object-nya harus dari data yang dibalikin useTina() (bukan data mentah sebelum diproses), di situ metadata _content_source yang dibutuhkan tinaField() nempel.

Contoh pemakaian

useTina() nerima ref response server yang lengkap (bukan cuma data yang udah di-unwrap). Dia butuh query dan variables di dalamnya buat kirim handshake ke Tina Admin. Cara paling gampang: tulis server route yang panggil tina/__generated__/client, terus pass ref hasil useAsyncData langsung ke useTina().

// server/api/posts/[slug].get.ts
import client from '../../../tina/__generated__/client'

export default defineEventHandler(async (event) => {
  const relativePath = `${getRouterParam(event, 'slug')}.md`
  const res = await client.queries.post({ relativePath })
  return { data: res.data, query: res.query, variables: res.variables }
})
<script setup lang="ts">
const route = useRoute()

const { data: response } = await useAsyncData(`post-${route.params.slug}`, () =>
  $fetch(`/api/posts/${route.params.slug}`),
)

const { data, isEditing, isInIframe } = useTina(response)
const post = computed(() => data.value?.post ?? {})
</script>

<template>
  <article>
    <div v-if="isInIframe" class="edit-badge">Tina Contextual Editing Active</div>
    <h1 :data-tina-field="tinaField(post, 'title')">{{ post.title }}</h1>
    <p :data-tina-field="tinaField(post, 'description')">{{ post.description }}</p>
  </article>
</template>

Copyright © 2026