---
title: "Variables"
description: "Display reactive values in your editor and synchronize editable slots."
canonical_url: "https://tiptap.dev/docs/composable-docs/variables/getting-started/overview"
---

# Variables

Display reactive values in your editor and synchronize editable slots.

**Variables** let you display values, such as a customer name or a calculated total, in your editor. When a value changes, every reference to it updates automatically.

The document stores a reference to the variable, while your application manages its value. You can also [bind variables to slots](https://tiptap.dev/docs/composable-docs/variables/guides/bind-slots.md) to keep editable content in sync.

> **Interactive demo:** [Variable](https://embed-pro.tiptap.dev/preview/Extensions/Variable)

> **Client-side only:**
>
> Variables run inside each editor instance. They do not provide a server API or synchronize runtime
> values between clients. Server-side support is on our roadmap. If you're interested, email us at
> [humans@tiptap.dev](mailto:humans@tiptap.dev).

## Install

First, [contact our team](https://tiptap.dev/contact-sales?form=pilot-program) to join the Tiptap Composable Docs pilot program.

Then, configure your package manager by following the [private registry guide](https://tiptap.dev/docs/guides/pro-extensions.md).

Then, install the package:

```bash
npm install @tiptap/core @tiptap/starter-kit @tiptap-pro/extension-variable
```

## Define and display a variable

First, import the editor and extensions:

```ts
import { Editor } from '@tiptap/core'
import StarterKit from '@tiptap/starter-kit'
import { Variable } from '@tiptap-pro/extension-variable'
```

Define a variable called `customer` and add the extension to your editor:

```ts
const editor = new Editor({
  extensions: [
    StarterKit,
    Variable.configure({
      variables: { customer: 'Ada' },
    }),
  ],
  content: '<p></p>',
})
```

Insert a reference at the current selection. It displays **Ada**:

```ts
editor.commands.insertVariable({ name: 'customer' })
```

Update the value. Every reference to `customer` now displays **Grace**:

```ts
editor.commands.setVariable({ name: 'customer', value: 'Grace' })
```

## Add and manage variables at runtime

You don't need to know every variable when you create the editor. Add a value or resolver later with `addVariable()`, then insert a reference:

```ts
editor.commands.addVariable({ name: 'company', value: 'Acme' })
editor.commands.insertVariable({ name: 'company' })

editor.commands.addVariable({
  name: 'customerLabel',
  value: ({ getText }) => `${getText('customer')} at ${getText('company')}`,
})
editor.commands.insertVariable({ name: 'customerLabel' })
```

`addVariable()` returns `false` if the name is empty or already registered. Use `setVariable()` to update an existing value, or `setVariables()` to replace a value or resolver:

```ts
editor.commands.setVariable({ name: 'company', value: 'Tiptap' })
editor.commands.setVariables({
  variables: { customerLabel: ({ getText }) => getText('customer').toUpperCase() },
})
```

Remove a variable with `removeVariable()`. Remove its dependent resolvers first, or remove them together with `removeVariables()`:

```ts
editor.commands.removeVariable({ name: 'customerLabel' })
editor.commands.removeVariable({ name: 'company' })
```

Existing references stay in the document and display an empty value after removal. Adding the same name again restores their display. Runtime definitions belong to this editor instance and are not saved in the document or reverted by document undo. For bound slots, removal [returns the variable to slot content](https://tiptap.dev/docs/composable-docs/variables/api-reference/extension.md#removevariable).

See the [command reference](https://tiptap.dev/docs/composable-docs/variables/api-reference/extension.md#commands) for bulk registration, removal, and failure behavior.

## Values and resolvers

Define values directly or calculate them with a function, called a **resolver**. Use `get()` to read another variable's raw value, or `getText()` to read it as a string. Replace `Variable.configure(...)` in your editor with:

```ts
Variable.configure({
  variables: {
    customer: 'Ada',
    quantity: 3,
    greeting: ({ getText }) => `Hello, ${getText('customer')}!`,
  },
})
```

With this configuration, changing `customer` also updates `greeting`:

```ts
editor.commands.setVariable({ name: 'customer', value: 'Grace' })
// greeting becomes "Hello, Grace!"
```

Values can also be objects or arrays. Objects that are not Tiptap content display as JSON:

```ts
editor.commands.setVariable({
  name: 'customer',
  value: { name: 'Ada', company: 'Acme' },
})
```

To display the name and company separately, define a resolver for each property using `get('customer')`, then insert references to those variables. Names such as `customer.name` do not look up object properties automatically.

Use Tiptap JSON to display formatted content:

```ts
editor.commands.setVariable({
  name: 'customer',
  value: { type: 'text', text: 'Ada', marks: [{ type: 'bold' }] },
})
```

## Connect variable values to external sources

A resolver can read data from your application. Create a customer object, a resolver that reads its name, and an editor that displays it:

```ts
let customer = { name: 'Ada' }

const refreshEditor = new Editor({
  extensions: [
    StarterKit,
    Variable.configure({
      variables: { customer: () => customer.name },
    }),
  ],
  content: '<p></p>',
})
refreshEditor.commands.insertVariable({ name: 'customer' })
```

Listen for an application event and refresh the resolver:

```ts
const events = new EventTarget()
const refresh = () => refreshEditor.commands.refreshVariables({ names: ['customer'] })
events.addEventListener('customer-change', refresh)
```

After changing the data, send the event. The editor now displays **Grace**:

```ts
customer = { name: 'Grace' }
events.dispatchEvent(new Event('customer-change'))
```

Remove the listener when the editor is destroyed:

```ts
refreshEditor.on('destroy', () => events.removeEventListener('customer-change', refresh))
```

## What is saved

The document saves the variable's name, not its value. Each editor supplies its own values.

Text inside a [bound slot](https://tiptap.dev/docs/composable-docs/variables/guides/bind-slots.md) is saved as normal document content.
