Version history
Going back to earlier drafts of something written with AI: a history sidebar in a document, a timeline you scrub through on a canvas, and two versions compared side by side.
Loading preview…
Install
- 1
Run this command in your Tailwind CSS project. It adds
components/ai/version-history-default.tsxand installs its dependencies.$ npx shadcn@latest add https://gradientdeck.com/ai-components/r/version-history-default.json
Usage & API
Example
import { VersionHistory } from "@/components/ai/version-history-default"
<VersionHistory
versions={[]}
selectedId="…"
onSelect={() => {}}
onRestore={() => {}}
onRename={() => {}}
/>Props VersionHistory
| Prop | Type & description | Required |
|---|---|---|
versions | DocVersion[]Newest first. The first one is the current document. | Required |
selectedId | string | Required |
onSelect | (id: string) => void | Required |
onRestore | (id: string) => void | Required |
onRename | (id: string, name: string) => void | Required |
docPath | string | Optional |
Dependencies
- React
- Tailwind CSS
- motion
- lucide-react
Implementation notes
Document sidebar is a full window. The title row shows a path, defaulting to Marketing, the current title, the time it was edited, two initials, a History mark, and a Share button. Share has no handler in the file. The article shows a word count and the title and body. On the current row those render as plain text. On an older row they render through a word diff, and a legend in the banner explains the green and red marks. Back to current reselects the first id. Restore this version calls onRestore with the selected id. The side panel is labelled Version history and counts the rows. Days are group headings. Each group is a listbox. Up and down arrows move the selection and the focus. A pencil on the row turns the name into a field with a forty-character limit. Enter or blur saves through onRename. Escape cancels. The current row wears a Current pill. The preview's article is a product announcement, with assistant and human rows across Today.
Example
import { CanvasTimeline } from "@/components/ai/version-history-scrubber"
<CanvasTimeline
steps={[]}
index={1}
onIndexChange={() => {}}
onRestore={() => {}}
/>Props CanvasTimeline
| Prop | Type & description | Required |
|---|---|---|
steps | CanvasStep[] | Required |
index | number | Required |
onIndexChange | (index: number) => void | Required |
onRestore | (index: number) => void | Required |
Dependencies
- React
- Tailwind CSS
- motion
- lucide-react
Implementation notes
Canvas timeline is the other full window. A thread titled Freight quotes for Q1 sits on the left from the extra-large breakpoint up. Each step shows the person's prompt, the assistant's reply, and a chip, Vendor shortlist, with the version number. A restore step is a single line, You restored, plus a chip, instead of a prompt pair. Future steps fade. The canvas header has the artifact title, previous and next arrows, a v N of total readout, and a slider labelled Version. Dragging the slider, or using arrow keys, Home, and End, changes the index. Dots mark steps, and a restore step's dot gets an amber ring. Hovering or dragging shows a tip with the version number and a short you and assistant line. On the latest step the header says Latest. On an older step it offers Latest, which jumps to the end, and Restore. The artifact in the preview is a vendor table. Some steps add a summary, a price column, sortable headers, or a Pick mark. A Still open list sits under the table. The thread's message box is visible, and its send button is disabled. The component does not submit that field.
Example
import { CompareVersions } from "@/components/ai/version-history-compare"
<CompareVersions
versions={[]}
leftId="…"
rightId="…"
onLeftChange={() => {}}
onRightChange={() => {}}
decisions={decisions}
onDecide={() => {}}
onSave={() => {}}
/>Props CompareVersions
| Prop | Type & description | Required |
|---|---|---|
versions | PolicyVersion[] | Required |
leftId | string | Required |
rightId | string | Required |
onLeftChange | (id: string) => void | Required |
onRightChange | (id: string) => void | Required |
decisions | Record<number, Decision>Keyed by block index. | Required |
onDecide | (block: number, decision: Decision | null) => void | Required |
onSave | () => void | Required |
saved | string | null | Optional |
Dependencies
- React
- Tailwind CSS
- motion
- lucide-react
Implementation notes
Compare versions opens on a help-centre article, Returns and refunds. The toolbar counts changed blocks and steps through them with previous and next. Sync scroll is a toggle, on by default, that ties the two panes' scroll positions. Each pane has a version menu. The left menu is the older side and uses a red dot. The right menu is the newer side and uses a green dot. A version already shown on the other side is disabled and labelled Shown on the other side. Changed blocks get a coloured rail. The left pane shows deletions. The right pane shows additions. A block missing on one side reads Not in this version or Removed. On the right, each change offers Accept these changes or Keep older. After a decision the line reads Accepted or Kept the older wording, with Undo. The footer counts how many changes are reviewed and how many were accepted, and a bar fills on wider screens. Accept the rest marks every undecided block accepted. Save as new version stays disabled until at least one block was accepted, then calls onSave. The preview's notices are the policy sections across several labelled drafts.
Choosing a layout
Use the document sidebar when the draft is the product and the history is a panel beside it. People can scan Today and Yesterday, name a version in place, and restore without leaving the article. The Share control and the two initial marks in the header are part of that chrome. Use the canvas timeline when the artifact was built in a thread and each user message produced the next snapshot. Scrubbing the slider, pressing a version chip in the thread, or using the arrows all set the same index. Use compare when keeping the newer wording is a decision per section, not a restore of the whole file. Accept these changes, Keep older, and Save as new version are that workflow.
Do not open the full history surface for a single suggested sentence. Prose diff already accepts or rejects inside the paragraph and stays the size of a card. Do not use compare to watch a picture or a table evolve. The compare panes are headings and paragraphs, with additions in green on the right and deletions in red on the left. The canvas is the variant that can hold a table, and in this file that table is a vendor shortlist with transit, on-time rate, an optional price, and notes. None of the variants record a version by themselves. Restoring, renaming, and saving call the parent, and the parent has to insert the new row.
Which variant is the document, the canvas, and the compare view?
default is the article plus the history sidebar, with rename and restore. scrubber is the thread, the artifact, and the version slider. Its export is the canvas timeline, not the sidebar component. compare is the two-pane review with per-block decisions and Save as new version. They do not share one props object. Each file has its own version shape.
Can both compare panes show the same version?
No. Each menu disables the id chosen on the other side, and that row explains it is shown on the other side. Keyboard and click both refuse that id. The panes can still be any other pair, and changing either pair resets the change navigator to the first difference.