LibreChat’s Artifacts feature enables AI to create substantial, self-contained content displayed in a separate UI window, including interactive React components, HTML pages, diagrams, and more.
What are Artifacts?
Artifacts are substantial pieces of content that:
Self-Contained Complete, standalone content users can modify
Interactive Live previews of code, diagrams, and apps
Reusable Content intended for use outside the chat
Iterative Easily modified and improved through conversation
Enabling Artifacts
Artifacts can be configured per agent:
endpoints :
agents :
capabilities :
- artifacts # Enable artifacts capability
Or set in agent model parameters:
{
name : 'Creative Assistant' ,
provider : 'anthropic' ,
model : 'claude-4.5-sonnet' ,
artifacts : 'default' , // 'default', 'shadcnui', or 'custom'
instructions : 'You are a creative assistant...'
}
Artifact Modes
Standard artifacts with all content types:
HTML pages
React components
SVG images
Mermaid diagrams
Markdown documents
Enhanced mode with shadcn/ui component library: Includes pre-built UI components for professional interfaces Provide your own artifact instructions: artifacts : 'custom' ,
additional_instructions : 'Your custom artifact guidelines...'
Artifact Types
React Components
Interactive React components with hooks and state:
::: artifact { identifier = "counter-app" type = "application/vnd.react" title = "Interactive Counter" }
import { useState } from 'react' ;
export default function Counter () {
const [ count , setCount ] = useState ( 0 );
return (
< div className = "p-8 text-center" >
< h1 className = "text-4xl font-bold mb-4" > Counter </ h1 >
< p className = "text-6xl mb-8" > { count } </ p >
< div className = "space-x-4" >
< button
className = "bg-blue-500 text-white px-6 py-3 rounded-lg hover:bg-blue-600"
onClick = { () => setCount ( count + 1 ) }
>
Increment
</ button >
< button
className = "bg-gray-500 text-white px-6 py-3 rounded-lg hover:bg-gray-600"
onClick = { () => setCount ( 0 ) }
>
Reset
</ button >
</ div >
</ div >
);
}
:::
Available Libraries :
react - Core React library with hooks
[email protected] - Icon library
recharts - Charting library
three.js - 3D graphics
date-fns - Date utilities
react-day-picker - Date picker component
shadcn/ui - UI components (in shadcnui mode)
HTML Pages
Single-file HTML with embedded CSS and JavaScript:
:::artifact{identifier="landing-page" type="text/html" title="Landing Page"}
<! DOCTYPE html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Product Landing </ title >
< style >
body {
font-family : -apple-system , BlinkMacSystemFont, 'Segoe UI' , sans-serif ;
margin : 0 ;
padding : 0 ;
background : linear-gradient ( 135 deg , #667eea 0 % , #764ba2 100 % );
color : white ;
}
.container {
max-width : 1200 px ;
margin : 0 auto ;
padding : 60 px 20 px ;
text-align : center ;
}
h1 {
font-size : 3 rem ;
margin-bottom : 20 px ;
}
.cta-button {
background : white ;
color : #667eea ;
padding : 15 px 40 px ;
border : none ;
border-radius : 50 px ;
font-size : 1.2 rem ;
cursor : pointer ;
transition : transform 0.2 s ;
}
.cta-button:hover {
transform : scale ( 1.05 );
}
</ style >
</ head >
< body >
< div class = "container" >
< h1 > Welcome to Our Product </ h1 >
< p style = "font-size: 1.5rem; margin-bottom: 40px;" >
The best solution for your needs
</ p >
< button class = "cta-button" onclick = " alert ('Thanks for your interest!')" >
Get Started
</ button >
</ div >
</ body >
</ html >
:::
SVG Graphics
Scalable vector graphics:
:::artifact{identifier="logo-design" type="image/svg+xml" title="Logo"}
< svg viewBox = "0 0 200 200" xmlns = "http://www.w3.org/2000/svg" >
< defs >
< linearGradient id = "grad1" x1 = "0%" y1 = "0%" x2 = "100%" y2 = "100%" >
< stop offset = "0%" style = "stop-color:rgb(255,165,0);stop-opacity:1" />
< stop offset = "100%" style = "stop-color:rgb(255,69,0);stop-opacity:1" />
</ linearGradient >
</ defs >
< circle cx = "100" cy = "100" r = "80" fill = "url(#grad1)" />
< path d = "M 60 100 L 100 60 L 140 100 L 100 140 Z" fill = "white" opacity = "0.8" />
< text x = "100" y = "180" font-family = "Arial" font-size = "20"
text-anchor = "middle" fill = "#333" > My Logo </ text >
</ svg >
:::
Mermaid Diagrams
Flowcharts, sequence diagrams, and more:
Markdown Documents
Formatted text with markdown:
:::artifact{identifier="technical-doc" type="text/markdown" title="API Documentation"}
# API Documentation
## Overview
This API provides access to our data services.
## Authentication
All requests require an API key in the header:
```bash
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.example.com/data
Endpoints
GET /users
Retrieve a list of users.
Parameters:
limit (optional): Number of results (default: 10)
offset (optional): Pagination offset
Response:
{
"users" : [
{ "id" : 1 , "name" : "John Doe" },
{ "id" : 2 , "name" : "Jane Smith" }
],
"total" : 100
}
Rate Limits
1000 requests per hour per API key
429 status code when exceeded
:::
## Creating Artifacts
### When to Use Artifacts
<Check>
**Good for Artifacts:**
- Substantial content (>15 lines)
- Content users will modify or iterate on
- Self-contained, reusable code
- Reports, presentations, documents
- Interactive tools and calculators
</Check>
<Warning>
**NOT for Artifacts:**
- Simple code snippets
- Brief explanations or examples
- Conversational responses
- One-off questions
- Context-dependent content
</Warning>
### Artifact Syntax
Artifacts use remark-directive syntax:
```markdown
:::artifact{identifier="unique-id" type="mime-type" title="Display Title"}
Your content here
:::
Required Attributes:
identifier: Unique kebab-case ID for the artifact
type: MIME type or content type
title: Human-readable title
Updating Artifacts
Reuse the same identifier to update an artifact:
:::artifact{identifier="my-counter" type="application/vnd.react" title="Counter v2"}
// Updated code here - same identifier, new content
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
// ... enhanced implementation
}
:::
Advanced Examples
Data Visualization with Recharts
::: artifact { identifier = "sales-chart" type = "application/vnd.react" title = "Sales Dashboard" }
import { LineChart , Line , XAxis , YAxis , CartesianGrid , Tooltip , Legend , ResponsiveContainer } from 'recharts' ;
const data = [
{ month: 'Jan' , revenue: 4000 , expenses: 2400 },
{ month: 'Feb' , revenue: 3000 , expenses: 1398 },
{ month: 'Mar' , revenue: 2000 , expenses: 9800 },
{ month: 'Apr' , revenue: 2780 , expenses: 3908 },
{ month: 'May' , revenue: 1890 , expenses: 4800 },
{ month: 'Jun' , revenue: 2390 , expenses: 3800 },
];
export default function SalesDashboard () {
return (
< div className = "p-8" >
< h1 className = "text-3xl font-bold mb-6" > Sales Dashboard </ h1 >
< ResponsiveContainer width = "100%" height = { 400 } >
< LineChart data = { data } >
< CartesianGrid strokeDasharray = "3 3" />
< XAxis dataKey = "month" />
< YAxis />
< Tooltip />
< Legend />
< Line type = "monotone" dataKey = "revenue" stroke = "#8884d8" strokeWidth = { 2 } />
< Line type = "monotone" dataKey = "expenses" stroke = "#82ca9d" strokeWidth = { 2 } />
</ LineChart >
</ ResponsiveContainer >
</ div >
);
}
:::
Interactive Calculator
::: artifact { identifier = "tip-calculator" type = "application/vnd.react" title = "Tip Calculator" }
import { useState } from 'react' ;
export default function TipCalculator () {
const [ bill , setBill ] = useState ( '' );
const [ tipPercent , setTipPercent ] = useState ( 15 );
const tipAmount = ( parseFloat ( bill ) || 0 ) * ( tipPercent / 100 );
const total = ( parseFloat ( bill ) || 0 ) + tipAmount ;
return (
< div className = "p-8 max-w-md mx-auto" >
< h1 className = "text-3xl font-bold mb-6" > Tip Calculator </ h1 >
< div className = "space-y-4" >
< div >
< label className = "block text-sm font-medium mb-2" > Bill Amount </ label >
< input
type = "number"
value = { bill }
onChange = { ( e ) => setBill ( e . target . value ) }
className = "w-full px-4 py-2 border rounded-lg"
placeholder = "0.00"
/>
</ div >
< div >
< label className = "block text-sm font-medium mb-2" >
Tip Percentage: { tipPercent } %
</ label >
< input
type = "range"
min = "0"
max = "30"
value = { tipPercent }
onChange = { ( e ) => setTipPercent ( parseInt ( e . target . value )) }
className = "w-full"
/>
</ div >
< div className = "bg-gray-100 p-4 rounded-lg space-y-2" >
< div className = "flex justify-between" >
< span > Tip Amount: </ span >
< span className = "font-bold" > $ { tipAmount . toFixed ( 2 ) } </ span >
</ div >
< div className = "flex justify-between text-xl" >
< span > Total: </ span >
< span className = "font-bold" > $ { total . toFixed ( 2 ) } </ span >
</ div >
</ div >
</ div >
</ div >
);
}
:::
ShadCN UI Components
With artifacts: 'shadcnui' mode:
::: artifact { identifier = "form-demo" type = "application/vnd.react" title = "Contact Form" }
import { useState } from 'react' ;
import { Button } from '/components/ui/button' ;
import { Input } from '/components/ui/input' ;
import { Alert , AlertDescription } from '/components/ui/alert' ;
export default function ContactForm () {
const [ name , setName ] = useState ( '' );
const [ email , setEmail ] = useState ( '' );
const [ submitted , setSubmitted ] = useState ( false );
const handleSubmit = ( e ) => {
e . preventDefault ();
setSubmitted ( true );
};
return (
< div className = "p-8 max-w-md mx-auto" >
< h1 className = "text-3xl font-bold mb-6" > Contact Us </ h1 >
{ submitted ? (
< Alert >
< AlertDescription >
Thank you, { name } ! We'll contact you at { email } .
</ AlertDescription >
</ Alert >
) : (
< form onSubmit = { handleSubmit } className = "space-y-4" >
< div >
< label className = "block text-sm font-medium mb-2" > Name </ label >
< Input
value = { name }
onChange = { ( e ) => setName ( e . target . value ) }
required
/>
</ div >
< div >
< label className = "block text-sm font-medium mb-2" > Email </ label >
< Input
type = "email"
value = { email }
onChange = { ( e ) => setEmail ( e . target . value ) }
required
/>
</ div >
< Button type = "submit" className = "w-full" >
Submit
</ Button >
</ form >
) }
</ div >
);
}
:::
Configuration
Endpoint Settings
Configure artifacts in OpenAI or Anthropic endpoints:
// OpenAI endpoint
{
endpoint : 'openAI' ,
model : 'gpt-4o' ,
artifacts : 'default' // Uses OpenAI-specific artifact format
}
// Anthropic endpoint
{
endpoint : 'anthropic' ,
model : 'claude-4.5-sonnet' ,
artifacts : 'shadcnui' // Uses Anthropic XML format with ShadCN
}
Provider Differences
Anthropic (Claude)
OpenAI (GPT)
Uses XML-style artifact tags
Native artifact support
Comprehensive artifact guidelines
Uses markdown directive format
Adapted artifact implementation
Consistent user experience
Best Practices
Complete Code : Always provide full, functional code without placeholders or ”…” ellipses
Unique Identifiers : Use descriptive, unique kebab-case identifiers for each artifact
Appropriate Type : Choose the right artifact type for your content
No Arbitrary Values : Don’t use arbitrary Tailwind values like h-[600px]
Placeholder Images : Use /api/placeholder/WIDTH/HEIGHT for images
Limitations
React Components
No external libraries beyond those listed
No form libraries (zod, hookform)
Components must use /components/ui/ imports (not @/components/)
Must be standalone with no required props
HTML
Single-file only (no external CSS/JS files)
External scripts only from https://cdnjs.cloudflare.com
No external images (use placeholder API)
General
One artifact per message (unless specifically requested)
Must be substantial content (>15 lines)
Should be self-contained and reusable
Agents Enable artifacts in agent configurations
Code Interpreter Execute code and generate visualizations
AI Models Compatible AI models and providers
Multimodal Process images for artifact generation