Skip to main content
Gremorie

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>

PropTypeDefaultDescription
classNamestring-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>

PropTypeDefaultDescription
tooltipstring-When set, wraps the button in a Tooltip and supplies the label. Doubles as sr-only text.
labelstring-Explicit accessible label. Overrides tooltip for sr-only text.
iconLucideIcon-Convenience for icon-only actions. Renders the icon at size-4.
variantButtonVariant"ghost"Forwarded to the underlying Button.
sizeButtonSize"sm"Forwarded to the underlying Button.
childrenReactNode-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.

PropTypeDefaultDescription
childrenReactNode<XIcon />Override the icon if you need a different close glyph.
variantButtonVariant"ghost"Forwarded to Button.
sizeButtonSize"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

  1. <Artifact> is the card shell. Sets flex-col + overflow-hidden so the header stays pinned while the content scrolls.
  2. <ArtifactHeader> is the muted top row. Use it to communicate what the artifact is, with optional description and trailing actions.
  3. <ArtifactActions> + <ArtifactAction> + <ArtifactClose> sit in the header's trailing slot.
  4. <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: ArtifactClose ships an sr-only "Close" label so the icon-only X is announced. ArtifactAction uses tooltip / label to set the accessible name on icon-only buttons.
  • Tooltip: When tooltip is supplied, the button is wrapped in a Tooltip + TooltipProvider. If you have a global TooltipProvider higher 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.
  • 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

On this page