Artifact
Generic card chrome for AI-generated objects. The wrapper around code, docs, charts, images and any other asset the model produces.
Overview
Artifact is the structural shell every AI-generated object lives inside: a bordered card with a muted header (title + description + actions), an ArtifactClose affordance and an ArtifactContent body that scrolls independently.
It is intentionally agnostic about what goes inside ArtifactContent. Compose it with CodeBlock for code artifacts, WebPreview for live HTML, Image for generated images, or your own React tree for charts and rich documents. The header surface stays consistent across artifact types so users learn the chrome once.
Preview
Landing page hero
Generated from your prompt - 3 sections.
Body content of the artifact - usually a CodeBlock, preview iframe, or composed view.
'use client';import { Artifact, ArtifactActions, ArtifactClose, ArtifactContent, ArtifactDescription, ArtifactHeader, ArtifactTitle,} from '@gremorie/rx-artifacts';export function ArtifactPreview() { return ( <Artifact className="max-w-2xl"> <ArtifactHeader> <ArtifactTitle>Landing page hero</ArtifactTitle> <ArtifactDescription> Generated from your prompt - 3 sections. </ArtifactDescription> <ArtifactActions> <ArtifactClose /> </ArtifactActions> </ArtifactHeader> <ArtifactContent> <p className="text-sm text-muted-foreground"> Body content of the artifact - usually a CodeBlock, preview iframe, or composed view. </p> </ArtifactContent> </Artifact> );}Installation
bash npx gremorie@latest add rx-artifact bash pnpm dlx gremorie@latest add rx-artifact bash yarn dlx gremorie@latest add rx-artifact bash bunx --bun gremorie@latest add rx-artifact Pulls in rx-forms (for Button) and rx-overlays (for Tooltip) so ArtifactAction works out of the box.
Usage
import {
Artifact,
ArtifactActions,
ArtifactClose,
ArtifactContent,
ArtifactDescription,
ArtifactHeader,
ArtifactTitle,
} from "@gremorie/rx-artifacts";
export function Example() {
return (
<Artifact>
<ArtifactHeader>
<ArtifactTitle>Landing page hero</ArtifactTitle>
<ArtifactDescription>3 sections</ArtifactDescription>
<ArtifactActions>
<ArtifactClose onClick={dismiss} />
</ArtifactActions>
</ArtifactHeader>
<ArtifactContent>{children}</ArtifactContent>
</Artifact>
);
}Angular edition planned for Phase 5h. Use the React edition for now, or open an issue to prioritize this primitive.
API
<Artifact>
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Extra classes on the root div. Useful for sizing (max-w-2xl, h-full). |
Extends all HTMLAttributes<HTMLDivElement>. Default chrome: rounded border, shadow-sm, vertical flex column.
<ArtifactHeader>
Border-bottom flex row with muted background. Place ArtifactTitle + ArtifactDescription on the left, ArtifactActions on the right.
Extends all HTMLAttributes<HTMLDivElement>.
<ArtifactTitle> / <ArtifactDescription>
Plain <p> elements. Title is text-sm font-medium, description is text-sm text-muted-foreground.
Extends all HTMLAttributes<HTMLParagraphElement>.
<ArtifactActions>
Flex container (gap-1) for action buttons. Place ArtifactAction and ArtifactClose inside.
Extends all HTMLAttributes<HTMLDivElement>.
<ArtifactAction>
| Prop | Type | Default | Description |
|---|---|---|---|
tooltip | string | - | When set, wraps the button in a Tooltip and supplies the label. Doubles as sr-only text. |
label | string | - | Explicit accessible label. Overrides tooltip for sr-only text. |
icon | LucideIcon | - | Convenience for icon-only actions. Renders the icon at size-4. |
variant | ButtonVariant | "ghost" | Forwarded to the underlying Button. |
size | ButtonSize | "sm" | Forwarded to the underlying Button. |
children | ReactNode | - | Falls back to icon when children is missing. |
When tooltip is set, the action wraps itself in a TooltipProvider + Tooltip. If your page already has a TooltipProvider at the root, that nesting is harmless (Radix de-duplicates).
<ArtifactClose>
Specialised ArtifactAction with a built-in XIcon. Carries aria-label="Close" via sr-only span.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | <XIcon /> | Override the icon if you need a different close glyph. |
variant | ButtonVariant | "ghost" | Forwarded to Button. |
size | ButtonSize | "sm" | Forwarded to Button. |
<ArtifactContent>
Scrollable body (overflow-auto p-4) with flex-1 so it fills the remaining height. Drop any node inside.
Extends all HTMLAttributes<HTMLDivElement>.
Composition
<Artifact>is the card shell. Setsflex-col+overflow-hiddenso the header stays pinned while the content scrolls.<ArtifactHeader>is the muted top row. Use it to communicate what the artifact is, with optional description and trailing actions.<ArtifactActions>+<ArtifactAction>+<ArtifactClose>sit in the header's trailing slot.<ArtifactContent>owns the body. Compose with any other Gremorie primitive (CodeBlock,WebPreview,Image,Chart, etc.).
Variations
Code artifact
The most common case: render the model's code output with line numbers and copy.
<Artifact>
<ArtifactHeader>
<ArtifactTitle>signin.tsx</ArtifactTitle>
<ArtifactActions>
<ArtifactAction tooltip="Open in editor" icon={ExternalLinkIcon} />
<ArtifactClose />
</ArtifactActions>
</ArtifactHeader>
<ArtifactContent>
<CodeBlock code={generated} language="tsx" showLineNumbers>
<CodeBlockCopyButton />
</CodeBlock>
</ArtifactContent>
</Artifact>Live web preview
Use WebPreview inside for a runnable artifact. The header explains what the user is looking at.
<Artifact className="h-[480px]">
<ArtifactHeader>
<ArtifactTitle>Landing page</ArtifactTitle>
<ArtifactDescription>Live preview</ArtifactDescription>
<ArtifactActions>
<ArtifactClose />
</ArtifactActions>
</ArtifactHeader>
<ArtifactContent className="p-0">
<WebPreview defaultUrl="/preview/landing">
<WebPreviewNavigation>
<WebPreviewUrl />
</WebPreviewNavigation>
<WebPreviewBody src="/preview/landing" />
</WebPreview>
</ArtifactContent>
</Artifact>Generated image artifact
<Artifact>
<ArtifactHeader>
<ArtifactTitle>chart.png</ArtifactTitle>
<ArtifactActions>
<ArtifactAction
tooltip="Download"
icon={DownloadIcon}
onClick={download}
/>
<ArtifactClose />
</ArtifactActions>
</ArtifactHeader>
<ArtifactContent>
<Image base64={imageBase64} mediaType="image/png" alt="Generated chart" />
</ArtifactContent>
</Artifact>Accessibility
- Keyboard: All actions are real
Buttons, so Tab order is natural and Enter / Space activate them. - ARIA:
ArtifactCloseships ansr-only"Close" label so the icon-only X is announced.ArtifactActionusestooltip/labelto set the accessible name on icon-only buttons. - Tooltip: When
tooltipis supplied, the button is wrapped in aTooltip+TooltipProvider. If you have a globalTooltipProviderhigher in the tree, the nested provider is a no-op. - Focus order: Header actions stay in document order so screen readers announce title -> description -> actions, matching the visual order.
Related
- Code Block - the most common content inside an artifact
- Web Preview - live HTML preview inside an artifact
- Image - base64 image surface for AI-generated images
- Tool - similar collapsible chrome, but for tool calls rather than artifacts