Composables
Route-aware page loading and headless content search.
Ginko exposes two public composables: useContentPage() and useContentSearch(). Import them from @lupinum/ginko-content/client. The Nuxt module also auto-imports useContentPage and the collision-safe search name useGinkoContentSearch.
useContentPage()
Resolve the current Nuxt route against one collection.
useContentPage(handle, options?): Promise<UseContentPageResult><script setup lang="ts">
import { createError } from '#imports'
import { useContentPage } from '@lupinum/ginko-content/client'
import { docs } from '~~/content.config'
definePageMeta({ key: route => route.path })
const { page, status, error } = await useContentPage(docs, {
fallback: true
})
if (!page.value) {
throw createError({ statusCode: 404, statusMessage: 'Document not found', fatal: true })
}
</script>
<template>
<ContentRenderer v-if="page" :value="page" />
</template>The page key reruns setup when the path changes, without remounting for query or
hash changes. The composable integrates with the Nuxt SSR payload and hides a
previous route's document while the next route is resolving. fatal: true makes
the same route-owned 404 policy reach Nuxt's error page during client navigation.
Options
Options may contain refs or getters.
| Option | Type | Default | Purpose |
|---|---|---|---|
locale | string | Current route locale | Override locale inference |
fallback | LocaleFallback | exact | Resolve a configured or explicit locale fallback |
select | string[] | all fields | Project authored fields |
populate | PopulateSpec | none | Resolve reference fields |
surround | boolean | { select? } | false | Load previous and next navigation items |
Setting surround performs one additional request. Pass true for the default projection or an object to select fields:
const { page, previous, next } = await useContentPage(docs, {
surround: { select: ['description', 'icon'] }
})Return value
| Field | Type | Purpose |
|---|---|---|
page | ComputedRef<LocalizedContentDocument | undefined> | Current matching document |
previous | ComputedRef<NavigationItem | null> | Previous item when surround is enabled |
next | ComputedRef<NavigationItem | null> | Next item when surround is enabled |
status | ComputedRef<string> | Nuxt async-data status |
error | ComputedRef<unknown> | Page or surround request error |
refresh() | () => Promise<void> | Refresh the page and optional surround request |
Returned documents use the document envelope. useContentPage() does not throw a 404, update <head>, or redirect from a fallback URL; the route component owns those policies.
useContentSearch()
Create headless search state for a combobox, modal, or command palette.
useContentSearch(options?): Promise<UseContentSearchResult>import { useContentSearch } from '@lupinum/ginko-content/client'
const search = await useContentSearch({
initialQuery: '',
limit: 8,
locale: computed(() => 'en')
})
search.setQuery('routing')
const selected = search.select(0)The configured content.search.engine supplies results. Passing a collection additionally loads that collection's search sections and search-shaped navigation:
import { docs } from '~~/content.config'
const { files, searchNavigation, results } = await useContentSearch({
collection: docs,
locale: computed(() => 'en')
})Keep this call outside <ClientOnly> when server-rendered search UI needs files or searchNavigation in its payload.
Options
| Option | Type | Default | Purpose |
|---|---|---|---|
initialQuery | MaybeRefOrGetter<string> | '' | Initial writable query value |
limit | MaybeRefOrGetter<number> | engine result count | Limit exposed results |
locale | MaybeRefOrGetter<string> | none | Filter results and collection data |
collection | Handle or dynamic name | none | Also load search sections and search navigation |
Return value
| Field | Purpose |
|---|---|
query | Writable search term ref |
results | Normalized, limited search results |
pending / error | Backend loading state |
activeIndex / activeResult | Current highlighted result |
hasQuery / hasResults / isEmpty | Derived rendering state |
setQuery(value) / reset() | Query controls |
next() / previous() / setActiveIndex(index) | Highlight controls |
select(index?) | Return a result or null without navigating |
files | Collection search sections; empty without collection |
searchNavigation | Search-shaped collection navigation; empty without collection |
Search errors are exposed through error, including disabled search, provider failures, and Pagefind loading failures. Each result contains collection and path, so routing does not need to infer collection identity from URL prefixes.
Other client exports
These are ordinary functions, not composables. getCollectionPath(),
findFirstNavigationPage(), and extractContentToc() are framework-free
derivations. querySiteData() is a one-shot async Nuxt query function:
| Export | Signature | Purpose |
|---|---|---|
getCollectionPath | (collection, options?) => string | Project a collection route from locale, slug, or path; localePrefix: false omits the application locale prefix |
findFirstNavigationPage | (items?) => item | null | Find the first route-bearing page depth-first, skipping structural nodes |
querySiteData | (key, options?) => Promise<{ key, locale?, data, updatedAt? }> | Read provider site data; options are locale and an optional custom fetcher |
extractContentToc | (content, options?) => Toc | Derive an H2–H4 table of contents from a Markdown string |
getCollectionPath() options are locale, slug, path, and localePrefix;
path takes precedence over slug. Locale mounts come from the collection
handle and cannot be overridden per call. A handle using inherited
i18n: true does not contain that inherited policy, so this pure helper
requires the explicit collection-local
i18n: { locales, defaultLocale } form instead of guessing.
extractContentToc() accepts depth, title, and searchDepth, with a maximum
heading depth of 4 by default.
For lists, pagination, navigation, backlinks, and exact document reads, compose
the one-shot async Nuxt query functions with
useAsyncData(). That composition gives Nuxt ownership of SSR payload transfer,
cache keys, reactive state, pending state, and errors. Pre-v3 query composable
names were removed rather than deprecated; the
Ginko version migration maps those
names to their replacements.