Artifacts are interactive documents that appear in a dedicated panel alongside the chat. They support real-time editing, version history, and specialized features for different content types.
Artifact types
The chatbot supports four types of artifacts, each with unique capabilities:
Text documents Rich text editing with AI-powered suggestions and version comparison
Code artifacts Syntax highlighting with Python code execution support
Image generation AI-generated images with version history
Spreadsheets CSV data editing and manipulation
Artifact system
The Artifact component provides a unified interface for all artifact types with animated transitions:
import { useArtifact } from "@/hooks/use-artifact" ;
import { textArtifact } from "@/artifacts/text/client" ;
import { codeArtifact } from "@/artifacts/code/client" ;
import { imageArtifact } from "@/artifacts/image/client" ;
import { sheetArtifact } from "@/artifacts/sheet/client" ;
export const artifactDefinitions = [
textArtifact ,
codeArtifact ,
imageArtifact ,
sheetArtifact ,
];
export function Artifact ({
chatId ,
messages ,
selectedModelId ,
} : ArtifactProps ) {
const { artifact , setArtifact } = useArtifact ();
const artifactDefinition = artifactDefinitions . find (
( definition ) => definition . kind === artifact . kind
);
return (
< AnimatePresence >
{ artifact . isVisible && (
< motion.div className = "fixed h-dvh" >
< artifactDefinition.content
content = { artifact . content }
status = { artifact . status }
/>
</ motion.div >
) }
</ AnimatePresence >
);
}
Text artifacts
Text artifacts provide a rich editing experience with AI-powered suggestions:
artifacts/text/client.tsx
import { Artifact } from "@/components/create-artifact" ;
import { Editor } from "@/components/text-editor" ;
import { DiffView } from "@/components/diffview" ;
export const textArtifact = new Artifact < "text" , TextArtifactMetadata >({
kind: "text" ,
description: "Useful for text content, like drafting essays and emails." ,
initialize : async ({ documentId , setMetadata }) => {
const suggestions = await getSuggestions ({ documentId });
setMetadata ({ suggestions });
},
onStreamPart : ({ streamPart , setArtifact }) => {
if ( streamPart . type === "data-textDelta" ) {
setArtifact (( draftArtifact ) => ({
... draftArtifact ,
content: draftArtifact . content + streamPart . data ,
isVisible: draftArtifact . content . length > 400 ,
status: "streaming" ,
}));
}
},
content : ({ mode , content , isCurrentVersion , onSaveContent }) => {
if ( mode === "diff" ) {
return < DiffView oldContent = { oldContent } newContent = { newContent } /> ;
}
return (
< Editor
content = { content }
isCurrentVersion = { isCurrentVersion }
onSaveContent = { onSaveContent }
/>
);
},
});
Text artifact toolbar
Text artifacts include quick actions for common editing tasks:
artifacts/text/client.tsx
toolbar : [
{
icon: < PenIcon /> ,
description: "Add final polish" ,
onClick : ({ sendMessage }) => {
sendMessage ({
role: "user" ,
parts: [{
type: "text" ,
text: "Please add final polish and check for grammar, add section titles for better structure, and ensure everything reads smoothly." ,
}],
});
},
},
{
icon: < MessageIcon /> ,
description: "Request suggestions" ,
onClick : ({ sendMessage }) => {
sendMessage ({
role: "user" ,
parts: [{
type: "text" ,
text: "Please add suggestions you have that could improve the writing." ,
}],
});
},
},
]
Code artifacts
Code artifacts support syntax highlighting and Python execution using Pyodide:
artifacts/code/client.tsx
import { CodeEditor } from "@/components/code-editor" ;
import { Console } from "@/components/console" ;
export const codeArtifact = new Artifact < "code" , Metadata >({
kind: "code" ,
description: "Useful for code generation; Code execution is only available for python code." ,
content : ({ metadata , setMetadata , ... props }) => {
return (
<>
< CodeEditor { ... props } />
{ metadata ?. outputs && (
< Console
consoleOutputs = { metadata . outputs }
setConsoleOutputs = { () => setMetadata ({ outputs: [] }) }
/>
) }
</>
);
},
});
Running Python code
The code artifact executes Python in the browser using Pyodide:
artifacts/code/client.tsx
actions : [
{
icon: < PlayIcon size = { 18 } /> ,
label: "Run" ,
description: "Execute code" ,
onClick : async ({ content , setMetadata }) => {
const runId = generateUUID ();
const outputContent : ConsoleOutputContent [] = [];
// Initialize Pyodide
const pyodide = await globalThis . loadPyodide ({
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/" ,
});
// Capture output
pyodide . setStdout ({
batched : ( output : string ) => {
outputContent . push ({
type: output . startsWith ( "data:image/png;base64" )
? "image"
: "text" ,
value: output ,
});
},
});
// Load required packages
await pyodide . loadPackagesFromImports ( content );
// Execute code
await pyodide . runPythonAsync ( content );
// Update outputs
setMetadata (( metadata ) => ({
... metadata ,
outputs: [ ... metadata . outputs , {
id: runId ,
contents: outputContent ,
status: "completed" ,
}],
}));
},
},
]
Matplotlib support
Code artifacts automatically handle matplotlib plots:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace( 0 , 10 , 100 )
y = np.sin(x)
plt.figure( figsize = ( 10 , 6 ))
plt.plot(x, y)
plt.title( 'Sine Wave' )
plt.show() # Automatically displays in the console
Image artifacts
Image artifacts display AI-generated images with version history:
artifacts/image/client.tsx
import { ImageEditor } from "@/components/image-editor" ;
export const imageArtifact = new Artifact ({
kind: "image" ,
description: "Useful for image generation" ,
onStreamPart : ({ streamPart , setArtifact }) => {
if ( streamPart . type === "data-imageDelta" ) {
setArtifact (( draftArtifact ) => ({
... draftArtifact ,
content: streamPart . data ,
isVisible: true ,
status: "streaming" ,
}));
}
},
content: ImageEditor ,
actions: [
{
icon: < CopyIcon size = { 18 } /> ,
description: "Copy image to clipboard" ,
onClick : ({ content }) => {
const img = new Image ();
img . src = `data:image/png;base64, ${ content } ` ;
img . onload = () => {
const canvas = document . createElement ( "canvas" );
canvas . width = img . width ;
canvas . height = img . height ;
const ctx = canvas . getContext ( "2d" );
ctx ?. drawImage ( img , 0 , 0 );
canvas . toBlob (( blob ) => {
if ( blob ) {
navigator . clipboard . write ([
new ClipboardItem ({ "image/png" : blob }),
]);
}
}, "image/png" );
};
},
},
],
});
Spreadsheet artifacts
Spreadsheet artifacts provide CSV editing and data manipulation:
artifacts/sheet/client.tsx
import { parse , unparse } from "papaparse" ;
import { SpreadsheetEditor } from "@/components/sheet-editor" ;
export const sheetArtifact = new Artifact < "sheet" , Metadata >({
kind: "sheet" ,
description: "Useful for working with spreadsheets" ,
content : ({ content , currentVersionIndex , onSaveContent , status }) => {
return (
< SpreadsheetEditor
content = { content }
currentVersionIndex = { currentVersionIndex }
saveContent = { onSaveContent }
status = { status }
/>
);
},
});
Spreadsheet artifacts include data analysis actions:
artifacts/sheet/client.tsx
toolbar : [
{
description: "Format and clean data" ,
icon: < SparklesIcon /> ,
onClick : ({ sendMessage }) => {
sendMessage ({
role: "user" ,
parts: [{
type: "text" ,
text: "Can you please format and clean the data?"
}],
});
},
},
{
description: "Analyze and visualize data" ,
icon: < LineChartIcon /> ,
onClick : ({ sendMessage }) => {
sendMessage ({
role: "user" ,
parts: [{
type: "text" ,
text: "Can you please analyze and visualize the data by creating a new code artifact in python?" ,
}],
});
},
},
]
Creating artifacts
The AI uses the createDocument tool to generate artifacts:
lib/ai/tools/create-document.ts
import { tool } from "ai" ;
import { z } from "zod" ;
export const createDocument = ({ session , dataStream }) =>
tool ({
description: "Create a document for a writing or content creation activities." ,
inputSchema: z . object ({
title: z . string (),
kind: z . enum ([ "text" , "code" , "image" , "sheet" ]),
}),
execute : async ({ title , kind }) => {
const id = generateUUID ();
// Notify client about new artifact
dataStream . write ({ type: "data-kind" , data: kind });
dataStream . write ({ type: "data-id" , data: id });
dataStream . write ({ type: "data-title" , data: title });
// Find document handler for this artifact kind
const documentHandler = documentHandlersByArtifactKind . find (
( handler ) => handler . kind === kind
);
// Generate artifact content
await documentHandler . onCreateDocument ({
id ,
title ,
dataStream ,
session ,
});
return {
id ,
title ,
kind ,
content: "A document was created and is now visible to the user." ,
};
},
});
Version history
All artifacts maintain version history with visual diff comparison:
const handleVersionChange = ( type : "next" | "prev" | "toggle" | "latest" ) => {
if ( ! documents ) return ;
if ( type === "latest" ) {
setCurrentVersionIndex ( documents . length - 1 );
setMode ( "edit" );
}
if ( type === "toggle" ) {
setMode (( currentMode ) => ( currentMode === "edit" ? "diff" : "edit" ));
}
if ( type === "prev" && currentVersionIndex > 0 ) {
setCurrentVersionIndex (( index ) => index - 1 );
} else if ( type === "next" && currentVersionIndex < documents . length - 1 ) {
setCurrentVersionIndex (( index ) => index + 1 );
}
};
Artifact content is automatically saved to the database with debouncing to prevent excessive writes.
Auto-save functionality
Artifacts automatically save changes with a 2-second debounce:
const handleContentChange = useCallback ( async ( updatedContent : string ) => {
if ( ! artifact ) return ;
mutate < Document []>(
`/api/document?id= ${ artifact . documentId } ` ,
async ( currentDocuments ) => {
const currentDocument = currentDocuments ?. at ( - 1 );
if ( currentDocument ?. content !== updatedContent ) {
await fetch ( `/api/document?id= ${ artifact . documentId } ` , {
method: "POST" ,
body: JSON . stringify ({
title: artifact . title ,
content: updatedContent ,
kind: artifact . kind ,
}),
});
return [ ... currentDocuments , {
... currentDocument ,
content: updatedContent ,
createdAt: new Date (),
}];
}
return currentDocuments ;
},
{ revalidate: false }
);
}, [ artifact , mutate ]);
const debouncedHandleContentChange = useDebounceCallback (
handleContentChange ,
2000
);
Chat interface Learn about the chat interface
Data persistence Understand how artifacts are stored