|Design System

AI Component

Artifact Card

Expandable container for AI-generated content — code blocks, charts, and documents that live alongside chat.

Preview

async function fetchAI(prompt: string) {
  const res = await fetch("/api/chat", {
    method: "POST",
    body: JSON.stringify({ prompt }),
  });
  return res.json();
}

Source

Full component implementation using the design system tokens.

tsx
"use client";

import { useState } from "react";
import { Code2, BarChart3, FileText, ChevronDown } from "lucide-react";

const typeIcons = {
  code: Code2,
  chart: BarChart3,
  document: FileText,
};

export function DSArtifactCard({
  type = "document",
  title,
  description,
  defaultExpanded = false,
  children,
}: {
  type?: "code" | "chart" | "document";
  title: string;
  description?: string;
  defaultExpanded?: boolean;
  children?: React.ReactNode;
}) {
  const [expanded, setExpanded] = useState(defaultExpanded);
  const Icon = typeIcons[type];

  return (
    <div className="border border-overlay/10 rounded-xl bg-surface overflow-hidden w-full">
      <button
        onClick={() => setExpanded(!expanded)}
        className="w-full flex items-center gap-3 px-4 py-3 hover:bg-overlay/5 transition-colors text-left"
      >
        <Icon className="w-4 h-4 text-accent shrink-0" />
        <div className="flex-1 min-w-0">
          <p className="text-xs font-semibold uppercase tracking-widest text-accent mb-0.5">
            Artifact
          </p>
          <p className="text-sm font-medium text-foreground truncate">{title}</p>
          {description && (
            <p className="text-xs text-tertiary truncate">{description}</p>
          )}
        </div>
        <ChevronDown
          className={`w-4 h-4 text-tertiary transition-transform duration-200 shrink-0 ${
            expanded ? "rotate-180" : ""
          }`}
        />
      </button>
      {expanded && children && (
        <div className="border-t border-overlay/5 px-4 py-4">{children}</div>
      )}
    </div>
  );
}

Props

All available props with types and defaults.

PropTypeDescription
title*stringArtifact title
type'code' | 'chart' | 'document'Content type — determines icon
descriptionstringBrief description of the artifact content
defaultExpandedbooleanWhether the card starts expanded
childrenReactNodeExpanded content

Variants

Code artifact

Collapsed code block with expand interaction.

Expanded content area for the code artifact.

tsx
<DSArtifactCard
  type="code"
  title="API Integration"
  description="fetch wrapper with error handling"
>
  <pre className="text-sm font-mono text-secondary">
    {codeContent}
  </pre>
</DSArtifactCard>

Chart artifact

Data visualization container.

Expanded content area for the chart artifact.

tsx
<DSArtifactCard
  type="chart"
  title="Revenue Breakdown"
  description="Q4 2024 by region"
>
  <ChartComponent data={data} />
</DSArtifactCard>

Document artifact

Long-form generated content.

Expanded content area for the document artifact.

tsx
<DSArtifactCard
  type="document"
  title="Project Brief"
  description="3 sections, 450 words"
>
  <div className="prose">{content}</div>
</DSArtifactCard>

Prompt Guide

Prompt Guide — Artifact Card

Use for

  • AI-generated code blocks alongside chat
  • Data visualizations created by AI
  • Generated documents, summaries, and reports
  • Any structured output that needs its own container

Don't use for

  • Static content cards — use Card component
  • Image galleries — artifacts are for generated content
  • Settings panels — use Card with form elements

AI Context

Artifact cards solve the 'content alongside conversation' problem. When an AI generates a code block, chart, or document, it lives in an artifact card — expandable, labeled by type, and visually distinct from chat messages. The collapsed state shows type icon + title + description so users can scan what was generated. The expanded state reveals the full content. In Claude-style interfaces, artifacts can be pinned to a side panel.