Documentation Index Fetch the complete documentation index at: https://docs.morphllm.com/llms.txt
Use this file to discover all available pages before exploring further.
VibeArtifact
VibeArtifact combines the Artifact container from AI Elements SDK with VibeFrame to create a complete component display experience. It includes Run, Copy, Regenerate, Download, Share actions and a Code/Preview toggle—everything users expect when interacting with generated components.
Basic Usage
import { VibeArtifact } from 'genkit/react'
function ComponentPreview ({ component }) {
return (
< VibeArtifact
name = { component . name }
description = { component . description }
code = { component . code }
data = { appData }
/>
)
}
This renders:
┌─────────────────────────────────────────────────────────────┐
│ Sales Dashboard │
│ Pipeline visualization · Updated 2 minutes ago │
│ ▶ 📋 🔄 ⬇ 📤 │ 👁/< >│
├─────────────────────────────────────────────────────────────┤
│ │
│ [Component Preview] │
│ │
└─────────────────────────────────────────────────────────────┘
Props
Prop Type Default Description namestringrequired Component name displayed in header codestringrequired React component code descriptionstring- Optional description dataRecord<string, unknown>{}Data passed to the component updatedAtDate- Timestamp for “Updated X ago” defaultView'preview' | 'code''preview'Initial view mode classNamestring- CSS class for container minHeightnumber150Minimum preview height maxHeightnumber500Maximum preview height onRun() => void- Called when Run is clicked onRegenerate() => void- Called when Regenerate is clicked onShare() => void- Called when Share is clicked
Built-in Actions
Button Icon Behavior Run ▶ Refreshes the iframe, re-executes component Copy 📋 Copies code to clipboard, shows checkmark Regenerate 🔄 Calls onRegenerate callback (only shown if provided) Download ⬇ Downloads code as {name}.tsx file Share 📤 Calls onShare callback (only shown if provided) Code/Preview 👁/< > Toggles between preview and code view
Handling Actions
function StudioPreview ({ component , prompt }) {
const [ isRegenerating , setIsRegenerating ] = useState ( false )
const handleRegenerate = async () => {
setIsRegenerating ( true )
const newComponent = await generateComponent ( prompt )
setComponent ( newComponent )
setIsRegenerating ( false )
}
const handleShare = async () => {
const shareUrl = await createShareLink ( component . id )
await navigator . clipboard . writeText ( shareUrl )
toast . success ( 'Share link copied!' )
}
return (
< VibeArtifact
name = { component . name }
description = { component . description }
code = { component . code }
data = { appData }
updatedAt = { component . updatedAt }
onRegenerate = { handleRegenerate }
onShare = { handleShare }
/>
)
}
View Modes
Preview Mode (Default)
Shows the rendered component in a VibeFrame:
< VibeArtifact
name = "Stats Card"
code = { code }
data = { data }
defaultView = "preview"
/>
Code Mode
Shows the raw code with syntax highlighting:
< VibeArtifact
name = "Stats Card"
code = { code }
data = { data }
defaultView = "code"
/>
Users can toggle between modes using the Code/Preview button.
Timestamps
Show when the component was last updated:
< VibeArtifact
name = "Dashboard Widget"
code = { code }
updatedAt = {new Date ( '2025-01-05T10:30:00' ) }
/>
// Displays: "Updated 2 minutes ago"
The timestamp automatically formats as:
“just now” (< 1 minute)
“X minutes ago” (< 1 hour)
“X hours ago” (< 1 day)
“X days ago” (< 1 week)
Full date (> 1 week)
Composition with Artifact Primitives
VibeArtifact is built on the Artifact primitives. For custom layouts, use them directly:
import {
Artifact ,
ArtifactHeader ,
ArtifactTitle ,
ArtifactDescription ,
ArtifactActions ,
ArtifactAction ,
ArtifactContent ,
} from 'genkit/react'
import { VibeFrame } from 'genkit/react'
function CustomArtifact ({ component }) {
return (
< Artifact >
< ArtifactHeader >
< div >
< ArtifactTitle > { component . name } </ ArtifactTitle >
< ArtifactDescription >
By { component . author }
</ ArtifactDescription >
</ div >
< ArtifactActions >
< ArtifactAction
icon = { Star }
tooltip = "Favorite"
onClick = { () => favorite ( component . id ) }
/>
< ArtifactAction
icon = { Trash }
tooltip = "Delete"
onClick = { () => deleteComponent ( component . id ) }
/>
</ ArtifactActions >
</ ArtifactHeader >
< ArtifactContent className = "p-0" >
< VibeFrame code = { component . code } data = { data } />
</ ArtifactContent >
</ Artifact >
)
}
Artifact Primitives
Artifact
Main container with border and shadow:
< Artifact className = "w-full" >
{ /* children */ }
</ Artifact >
Header with title and actions:
< ArtifactHeader >
< div >
< ArtifactTitle > Component Name </ ArtifactTitle >
< ArtifactDescription > Description </ ArtifactDescription >
</ div >
< ArtifactActions >
{ /* action buttons */ }
</ ArtifactActions >
</ ArtifactHeader >
ArtifactAction
Action button with optional tooltip:
< ArtifactAction
icon = { Copy }
tooltip = "Copy to clipboard"
onClick = { () => copyCode () }
/>
// With custom content
< ArtifactAction tooltip = "Custom action" >
< MyIcon />
</ ArtifactAction >
ArtifactContent
Scrollable content area:
< ArtifactContent className = "p-0" >
< VibeFrame code = { code } />
</ ArtifactContent >
ArtifactClose
Close button (for modal/panel usage):
< ArtifactClose onClick = { () => setOpen ( false ) } />
Styling
VibeArtifact uses Tailwind CSS and respects your theme:
// Light mode
< VibeArtifact className = "bg-white" ... />
// Dark mode (automatic with dark: classes)
< VibeArtifact className = "dark:bg-gray-900" ... />
// Custom width
< VibeArtifact className = "max-w-2xl mx-auto" ... />
Example: Full Studio Integration
'use client'
import { useState } from 'react'
import { VibeArtifact } from 'genkit/react'
interface Component {
id : string
name : string
description : string
code : string
updatedAt : Date
}
export function VibeStudio () {
const [ component , setComponent ] = useState < Component | null >( null )
const [ prompt , setPrompt ] = useState ( '' )
const handleGenerate = async () => {
const response = await fetch ( '/api/vibe/generate' , {
method: 'POST' ,
body: JSON . stringify ({ prompt })
})
const data = await response . json ()
setComponent ({
... data . component ,
updatedAt: new Date ()
})
}
const handleRegenerate = () => {
handleGenerate ()
}
const handleSave = async () => {
await fetch ( '/api/vibe/save' , {
method: 'POST' ,
body: JSON . stringify ( component )
})
toast . success ( 'Saved to library!' )
}
const handleShare = async () => {
const url = ` ${ window . location . origin } /shared/ ${ component . id } `
await navigator . clipboard . writeText ( url )
toast . success ( 'Share link copied!' )
}
return (
< div className = "grid grid-cols-2 h-screen" >
{ /* Chat Panel */ }
< div className = "border-r p-4" >
< input
value = { prompt }
onChange = { ( e ) => setPrompt ( e . target . value ) }
placeholder = "Describe your component..."
className = "w-full p-3 border rounded"
/>
< button onClick = { handleGenerate } >
Generate
</ button >
</ div >
{ /* Preview Panel */ }
< div className = "p-6 bg-muted/30" >
{ component ? (
<>
< VibeArtifact
name = { component . name }
description = { component . description }
code = { component . code }
data = { sampleData }
updatedAt = { component . updatedAt }
onRegenerate = { handleRegenerate }
onShare = { handleShare }
/>
< button
onClick = { handleSave }
className = "mt-4 w-full"
>
Save to Library
</ button >
</>
) : (
< EmptyState />
) }
</ div >
</ div >
)
}
Next Steps
VibeFrame Learn about the secure rendering engine
Storage Persist components to your database