Skip to main content
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:
components/artifact.tsx
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 toolbar

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:
components/artifact.tsx
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:
components/artifact.tsx
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