---
title: createTimeline - Bounded Undo/Redo System for Vue 3
meta:
- name: description
  content: Bounded undo/redo system with fixed-size history. Built on createRegistry for state management with automatic overflow handling and time-travel debugging.
- name: keywords
  content: createTimeline, timeline, undo, redo, history, time travel, Vue 3, state management, registry
features:
  category: Composable
  label: 'E: createTimeline'
  github: /composables/createTimeline/
  level: 3
related:
  - /composables/registration/create-registry
  - /composables/registration/create-queue
---

# createTimeline

Bounded undo/redo history with a configurable size limit; older entries overflow into a buffer you can still undo back into.

<DocsPageFeatures :frontmatter />

## Usage

The `createTimeline` composable extends `createRegistry` to provide undo/redo functionality with a bounded history. When the timeline reaches its size limit, older items are moved to an overflow buffer, allowing you to undo back to them while maintaining a fixed active timeline size.

```ts collapse
import { createTimeline } from '@vuetify/v0'

const timeline = createTimeline({ size: 10 })

// Register actions
timeline.register({ id: 'action-1', value: 'Created document' })
timeline.register({ id: 'action-2', value: 'Added title' })
timeline.register({ id: 'action-3', value: 'Added paragraph' })

console.log(timeline.size) // 3

// Undo the last action
timeline.undo()
console.log(timeline.size) // 2

// Redo the undone action
timeline.redo()
console.log(timeline.size) // 3
```

## Context / DI

Use `createTimelineContext` to share a timeline instance across a component tree:

```ts
import { createTimelineContext } from '@vuetify/v0'

export const [useHistory, provideHistory, history] =
  createTimelineContext({ namespace: 'my:history', size: 50 })

// In parent component
provideHistory()

// In child component
const timeline = useHistory()
timeline.register({ id: 'action-1', value: 'Created item' })
timeline.undo()
```

## Architecture

`createTimeline` extends `createRegistry` with bounded history and overflow management:

```mermaid "Timeline Hierarchy"
flowchart TD
  createRegistry --> createTimeline
  createTimeline --> undo/redo
  createTimeline --> overflow[overflow buffer]
  createTimeline --> cursor[history cursor]
```

## Options

| Option | Type | Default | Notes |
| - | - | - | - |
| `size` | `number` | `10` | Maximum number of entries in the active timeline. When exceeded, the oldest entry moves to an internal overflow buffer — it remains accessible via `undo()` but no longer counts against the limit |

## Reactivity

`createTimeline` uses **minimal reactivity** like its parent `createRegistry`. History state is managed internally without reactive primitives.

> [!TIP] Need reactive history?
> Wrap with `useProxyRegistry(timeline)` for full template reactivity on the active timeline.

## Examples

::: gn-example
/composables/create-timeline/context.ts 2
/composables/create-timeline/CanvasProvider.vue 3
/composables/create-timeline/CanvasConsumer.vue 4
/composables/create-timeline/canvas.vue 1

### Drawing Canvas

A freehand drawing canvas split into four files demonstrating timeline-powered undo/redo:

| File | Role |
|------|------|
| `context.ts` | Defines `Point`, `Stroke`, `CanvasContext` types and the DI pair |
| `CanvasProvider.vue` | Creates the timeline, tracks redo state, exposes `add`/`undo`/`redo`/`clear` |
| `CanvasConsumer.vue` | Owns the `<canvas>` element, mouse/touch handlers, and render loop |
| `canvas.vue` | Entry point — wraps Provider around Consumer |

```mermaid "Provider/Consumer Data Flow"
graph LR
  A["context.ts"]:::info -->|"provideCanvas()"| B["CanvasProvider"]:::success
  A -->|"useCanvas()"| C["CanvasConsumer"]:::warning
  B -->|"wraps"| C
```

**Key patterns:**

- Provider owns `createTimeline` + `useProxyRegistry` — consumer never touches the timeline directly
- `strokes` computed maps `proxy.values` to raw `Stroke[]` — consumer only sees domain data
- `redoStackSize` tracked manually via `shallowRef` since redo stack is internal to the timeline
- `watchEffect` in consumer reads `strokes.value` for reactive canvas re-rendering
- History bar visualizes the 20-slot bounded timeline capacity

Draw on the canvas, then use Undo/Redo to time-travel through your strokes.

:::

## FAQ

::: faq

??? What happens when the timeline exceeds its `size` limit?

The oldest entry moves to an internal overflow buffer. It's still reachable via `undo()`, but it no longer counts against the size limit — so the active timeline stays a fixed size while older history remains recoverable.

??? When should I use createTimeline vs createQueue?

Both extend createRegistry, but for opposite jobs. createTimeline is bounded undo/redo history with a cursor and overflow buffer. [createQueue](/composables/registration/create-queue) is a time-based FIFO with auto-timeout and pause/resume. Use timeline for time-travel, queue for auto-dismissing sequential items.

??? How do I make the active timeline reactive in my template?

createTimeline inherits createRegistry's minimal reactivity. Wrap it with `useProxyRegistry(timeline)` for full template reactivity on the active timeline.

??? How do I tell when there's something to redo?

The redo stack is internal to the timeline and isn't exposed as a reactive property. Track it yourself with a `shallowRef` — the canvas example keeps a `redoStackSize` ref in sync as the user undoes and redoes, then drives the Redo button's state from it.

:::

<DocsApi />
