> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qirtaas.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Vue

> Idiomatic Vue 3 components wrapping the Qirtaas mount API.

`@qirtaas/vue` wraps [`@qirtaas/core`](/sdk/editor)'s mount API in two
components: `<QirtaasEditor>` and `<QirtaasRenderer>`. Vue 3 is a peer
dependency — the wrapper shares your app's Vue.

```bash theme={null}
npm install @qirtaas/vue
```

## QirtaasEditor

```vue theme={null}
<script setup lang="ts">
import { ref } from "vue";
import { QirtaasEditor } from "@qirtaas/vue";
import type { SaveState } from "@qirtaas/vue";

const editor = ref<InstanceType<typeof QirtaasEditor> | null>(null);
const saveState = ref<SaveState>("idle");

async function getToken() {
  const res = await fetch("/api/qirtaas-token", { method: "POST" });
  const { token } = await res.json();
  return token;
}
</script>

<template>
  <!-- The editor fills its container — give it a bounded height. -->
  <div style="height: 70vh">
    <QirtaasEditor
      ref="editor"
      :get-token="getToken"
      locale="ar"
      theme="light"
      @document-created="(id) => saveIdSomewhere(id)"
      @save-state-change="(s) => (saveState = s)"
    />
  </div>
</template>
```

<Warning>
  The editor owns an internal scroll view (pinned toolbar, scrolling body) and
  fills its container — the parent element must give it a **bounded height**
  (e.g. a sized dialog body or `h-[60vh]`).
</Warning>

### Props

Props mirror [`EditorMountOptions`](/sdk/editor#editormountoptions), plus the
connection config (the wrapper creates its client internally):

<ParamField path="getToken" type="() => Promise<string> | string" required>
  Returns a short-lived embed token. Called on init, before expiry, and on
  `401`. See [Authentication](/backend/authentication).
</ParamField>

<ParamField path="apiUrl" type="string" default="https://api.qirtaas.io">
  Qirtaas API base URL.
</ParamField>

<ParamField path="documentId" type="string">
  Existing document to load. Omit to lazy-create on first edit (the
  `documentCreated` event delivers the new id).
</ParamField>

<ParamField path="initialContent" type="Json | null">
  Initial content (TipTap JSON) when not loading from a `documentId`.
</ParamField>

<ParamField path="locale" type="&#x22;en&#x22; | &#x22;ar&#x22;" />

<ParamField path="theme" type="&#x22;light&#x22; | &#x22;dark&#x22;" />

<ParamField path="readOnly" type="boolean" default="false" />

<ParamField path="autofocus" type="boolean" />

<ParamField path="autosave" type="AutosaveOptions">
  See [Types](/sdk/types#autosaveoptions). Set `{ enabled: false }` and call
  `save()` on the template ref to drive persistence yourself.
</ParamField>

### Events

Each [editor callback](/sdk/editor#callbacks) is emitted as a Vue event:

| Event                | Payload                                         |
| -------------------- | ----------------------------------------------- |
| `@ready`             | —                                               |
| `@change`            | `json: Json`                                    |
| `@save-state-change` | `state: SaveState`                              |
| `@document-created`  | `id: string`                                    |
| `@error`             | `code: ErrorCode, detail?: unknown`             |
| `@token-expired`     | —                                               |
| `@event`             | `name: string, props?: Record<string, unknown>` |

### Live updates vs. remount

The component mounts the editor **once** (`onMounted`). Only two props are
watched after mount:

* `theme` — forwarded to `setTheme`
* `readOnly` — forwarded to `setEditable`

Changing anything else (`documentId`, `getToken`, `locale`, …) requires a
remount — give the component a `:key` that changes with them:

```vue theme={null}
<QirtaasEditor :key="docId" :document-id="docId" :get-token="getToken" />
```

### Exposed methods

Available on the template ref:

<ResponseField name="getJSON()" type="Json | null">
  Current editor content (TipTap JSON).
</ResponseField>

<ResponseField name="save()" type="Promise<void>">
  Force an immediate save of pending changes.
</ResponseField>

<ResponseField name="setEditable(editable)" type="void" />

<ResponseField name="setTheme(theme)" type="void" />

## QirtaasRenderer

Read-only display. Supply exactly **one** auth source — `share-token`,
`get-token`, or `get-signature` (see [Renderer auth modes](/sdk/renderer#auth-modes)).

```vue theme={null}
<QirtaasRenderer
  :document-id="docId"
  :get-signature="() => fetchSignature(docId)"
  locale="ar"
  theme="light"
  @error="(code) => report(code)"
/>
```

### Props

<ParamField path="apiUrl" type="string" default="https://api.qirtaas.io" />

<ParamField path="documentId" type="string">
  Document to render. With `shareToken`, the token resolves the document.
</ParamField>

<ParamField path="shareToken" type="string">Public read.</ParamField>

<ParamField path="getToken" type="() => Promise<string> | string">
  Own-document read (embed token).
</ParamField>

<ParamField path="getSignature" type="() => Promise<{ signature: string; exp: number }>">
  Cross-user read (per-document HMAC signature).
</ParamField>

<ParamField path="locale" type="&#x22;en&#x22; | &#x22;ar&#x22;" />

<ParamField path="theme" type="&#x22;light&#x22; | &#x22;dark&#x22;" />

Events: `@ready`, `@error`. The template ref exposes `setTheme(theme)`. As with
the editor, only `theme` is live — remount (via `:key`) for anything else.

## Imperative client operations

For mount-less operations (e.g. driving a document list view), the package
re-exports the [client](/sdk/client):

```ts theme={null}
import { createQirtaasClient } from "@qirtaas/vue";

const qirtaas = createQirtaasClient({ getToken: fetchEmbedToken });
const docs = await qirtaas.listDocuments(); // [{ id, title, … }]
await qirtaas.deleteDocument(id);
```
