Artifact

Pro

The thing an agent makes, kept out of the thread. A compact card sits in the conversation; open it and a pane beside the chat shows the result, its versions and its code. Ask for a change and the card says so while the pane catches up.

Build a pricing card for Koala Pro with monthly and annual billing.
Here is a pricing card for Pro, built from your Button and Badge. The annual price leads, with the yearly total underneath.
Pricing cardReact component
v3
Pricing card
Version 3 of 3

Pro

$24/month

$288 billed yearly

  • Every Pro component
  • Figma kit
  • Priority support
import { Badge } from "@/components/ui/badge"import { Button } from "@/components/ui/button"export function PricingCard() {  return (    <div className="flex flex-col gap-4 rounded-xl p-5 ring-1 ring-edge">      <div className="flex items-center justify-between">        <p className="font-medium">Pro</p>      </div>      <p className="text-3xl font-semibold">$24<span>/month</span></p>      <p className="text-sm text-muted-foreground">$288 billed yearly</p>      <ul className="flex flex-col gap-2 text-sm">        <li>Every Pro component</li>        <li>Figma kit</li>        <li>Priority support</li>      </ul>      <Button className="w-full">Start free trial</Button>    </div>  )}

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add artifact

Usage#

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Anatomy#

Two pieces that share a status. The card lives in the thread: an icon tile, a title over a short description, the version and an Open action. The pane lives beside it: a header with the title, the version stepper, the Preview / Code switch and the actions, over a content sheet that holds the preview, the code, the empty state or the skeleton.

import {  ArtifactCard,  ArtifactCardIcon,  ArtifactCardHeading,  ArtifactCardTitle,  ArtifactCardDescription,  ArtifactCardVersion,  ArtifactCardStatus,  ArtifactCardAction,  Artifact,  ArtifactHeader,  ArtifactTitle,  ArtifactVersion,  ArtifactTabs,  ArtifactActions,  ArtifactAction,  ArtifactCopy,  ArtifactContent,  ArtifactPreview,  ArtifactCode,  ArtifactEmpty,  ArtifactSkeleton,} from "@/components/ui/artifact"<ArtifactCard>  <ArtifactCardIcon />  <ArtifactCardHeading>    <ArtifactCardTitle />    <ArtifactCardDescription />  </ArtifactCardHeading>  <ArtifactCardStatus />  <ArtifactCardVersion />  <ArtifactCardAction /></ArtifactCard><Artifact>  <ArtifactHeader>    <ArtifactTitle />    <ArtifactVersion />    <ArtifactTabs />    <ArtifactActions>      <ArtifactCopy />      <ArtifactAction />    </ArtifactActions>  </ArtifactHeader>  <ArtifactContent>    <ArtifactSkeleton />    <ArtifactPreview />    <ArtifactCode />    <ArtifactEmpty />  </ArtifactContent></Artifact>

Card states#

Four states, and they all live where your eye already is. The icon tile cross-fades to a spinner while the agent works and to a warning when it gives up. While generating, the title sweeps and the description holds a shimmer bar in its own footprint, so the card does not grow when the words arrive. While updating, the version chip opens to v3 → v4: the number you know stays put and only the new one is added.

Q3 launch briefDocument
Pricing cardReact component
v3
Signups by weekChart
v3tov4
Onboarding emailCouldn't finish, the request timed out
v1

Play the lifecycle once to see the hand-offs: generating, ready, updating, then ready on the next version.

useBilling hookTypeScript

Types#

type picks the glyph and the fallback description: document, code, app, chart or image. Pass your own glyph as the icon's children for anything else.

Q3 launch briefDocument
useBilling hookTypeScript
Pricing cardReact component
Signups by weekChart
Koala mascot, flatImage

Card to pane#

The card and the pane share nothing but your state, which keeps them free to live in different trees: the card inside a message, the pane in a split, a sheet or an AI Panel. Hold one open flag and one status per artifact. The card's action sets it, the pane's close clears it, and open on the card keeps it lifted while its pane is showing so you can tell which card the pane belongs to. Send a change from the composer below: the card switches to updating, the pane dims and sweeps its title, then follows to the new version on its own.

Build a pricing card for Koala Pro with monthly and annual billing.
Here is a pricing card for Pro, built from your Button and Badge. The annual price leads, with the yearly total underneath.
Pricing cardReact component
v3
Pricing card
Version 3 of 3

Pro

$24/month

$288 billed yearly

  • Every Pro component
  • Figma kit
  • Priority support
import { Badge } from "@/components/ui/badge"import { Button } from "@/components/ui/button"export function PricingCard() {  return (    <div className="flex flex-col gap-4 rounded-xl p-5 ring-1 ring-edge">      <div className="flex items-center justify-between">        <p className="font-medium">Pro</p>      </div>      <p className="text-3xl font-semibold">$24<span>/month</span></p>      <p className="text-sm text-muted-foreground">$288 billed yearly</p>      <ul className="flex flex-col gap-2 text-sm">        <li>Every Pro component</li>        <li>Figma kit</li>        <li>Priority support</li>      </ul>      <Button className="w-full">Start free trial</Button>    </div>  )}

Version stepping#

Each request makes a version, and earlier ones stay one step away. Stepping back slides the content right, stepping forward slides it left, and the number in the read-out rolls the same way, so you always know which direction you went. Pass history and the read-out opens a menu of every version with a line about what changed.

Launch announcement
Version 4 of 4

Forty new components, one token layer

Koala UI 2 is out. Forty new components, a rebuilt token layer, four themes.

Set density once on the shell and every table, form and menu follows.

Upgrade with one command. Nothing in your app has to change.

Preview and code#

Add ArtifactTabs and the preview and the code become two views of one sheet. Leave it out and whichever parts you render simply show, so a document needs no tabs at all. For a live app, pass src to the preview and it renders a sandboxed iframe that fades in once it has loaded.

Waitlist form

Join the Koala beta

import { Button } from "@/components/ui/button"import { InputField, InputRoot } from "@/components/ui/input"export function WaitlistForm() {  return (    <form className="flex w-full max-w-sm flex-col gap-3">      <p className="font-medium">Join the Koala beta</p>      <InputRoot>        <InputField type="email" placeholder="you@company.com" />      </InputRoot>      <Button type="submit">Request access</Button>    </form>  )}

Empty and building#

Before anything exists, ArtifactEmpty tells the reader what the pane is for. While the first version is generating, ArtifactSkeleton takes the sheet with shimmer lines in the shape of a page; the preview and code wait for ready, so you can leave all three in the markup and let the status decide.

Artifact
Your artifact appears here

Ask for a document, a component or a chart and it opens in this pane.

Q3 launch brief
Building the artifact

In an AI Panel#

Inside an AI Panel the panel is already the frame, so use variant="plain": the tint goes and the header sits on the body's own inset, while the content keeps its sheet so the result still reads as one object. Give it a height and it scrolls inside, under the panel's composer.

Koala Assistant
Drafting in your workspace
Draft the release note for Koala UI 2.
Release note
Version 4 of 4

Forty new components, one token layer

Koala UI 2 is out. Forty new components, a rebuilt token layer, four themes.

Set density once on the shell and every table, form and menu follows.

Upgrade with one command. Nothing in your app has to change.

API reference#

ArtifactCard

The in-thread card: what was made, its version and an Open action. The context every card part reads. Forwards native <div> props. Every part accepts className, merged last.

PropTypeDefaultDescription
status"generating" | "ready" | "updating" | "error""ready"Drives the icon column, the title's sweep, the description skeleton, the version chip and aria-busy (generating or updating).
type"document" | "code" | "app" | "chart" | "image""document"Picks the glyph in ArtifactCardIcon and the fallback wording of ArtifactCardDescription.
versionnumber-The latest version, shown by ArtifactCardVersion. Leave it out while the first version is still generating.
openbooleanfalseThe card's pane is showing. The card stays lifted and its glyph takes full ink.
Data attributeDescription
data-statusThe card's status.
data-typeThe card's type.
data-openPresent while open.

ArtifactCardIcon

The 40px tile. Shows the type's glyph (or your children) and cross-fades to a spinner while generating or updating and a warning on error. aria-hidden. Renders a <span>.

ArtifactCardHeading

Stacks the title over the description and takes the free width. Renders a <div>.

ArtifactCardTitle

What was made. Sweeps while generating or updating, and names the Open action. Renders a <span>.

ArtifactCardDescription

A short line under the title, the type's name by default. While generating it holds a shimmer bar in the same footprint; on error it turns destructive. Renders a <span>.

ArtifactCardVersion

A Badge reading v3. While updating, → v4 opens beside it, so the number you know stays put. Renders nothing without a version. Forwards Badge props.

PropTypeDefaultDescription
childrenReact.ReactNode-Your own wording instead of the version.

ArtifactCardStatus

An optional chip worded and toned from status: Generating, Ready, Updating or Failed. Forwards Badge props.

PropTypeDefaultDescription
variantBadgeProps["variant"]-Overrides the tone the status picks.
childrenReact.ReactNode-Overrides the wording.

ArtifactCardAction

The Open button. Its hit area stretches over the whole card, its focus ring moves to the card, and its accessible name includes the title ("Open Pricing card"). Forwards Button props.

PropTypeDefaultDescription
childrenReact.ReactNode"Open"The label, "Retry" on a failed card for instance.
variantButtonProps["variant"]"ghost"Button variant.

Artifact

The pane. Holds the version, the Preview / Code view and the status every pane part reads. A Koala Tabs root underneath, so it forwards its props.

PropTypeDefaultDescription
status"generating" | "ready" | "updating" | "error""ready"generating shows ArtifactSkeleton and holds the preview and code back; updating sweeps the title and dims the content.
variant"card" | "plain""card"card is the tinted frame with the content as a sheet set 8px in; plain drops the frame for an AI Panel or a page that already frames it.
density"comfortable" | "compact"-Header inset and preview padding. Inherits the nearest DensityProvider (compact with none).
versionsnumber1How many versions exist. When it grows and you were on the latest, the pane follows to the new one.
versionnumber-Controlled version, 1-based.
defaultVersionnumber-Initial version. The latest by default.
onVersionChange(version: number) => void-Called when the stepper or the history picks a version.
view"preview" | "code"-Controlled view, when ArtifactTabs is present.
defaultView"preview" | "code""preview"Initial view.
onViewChange(view: "preview" | "code") => void-Called when the tabs switch view.
Data attributeDescription
data-statusThe pane's status.

ArtifactHeader

The bar above the content. Wraps to a second line on a narrow pane. Renders a <div>.

ArtifactTitle

The artifact's name. Sweeps while generating or updating. Renders a <div>.

ArtifactVersion

Previous and next around a "3 of 4" read-out in tabular-nums. The number rolls in the direction you stepped and the content slides the same way. Renders a role="group" <div>.

PropTypeDefaultDescription
history{ label: React.ReactNode; description?: React.ReactNode }[]-One entry per version, oldest first. Turns the read-out into a menu that jumps to any version, newest on top.
previousLabelstring"Previous version"Accessible name and tooltip of the back step.
nextLabelstring"Next version"Accessible name and tooltip of the forward step.
historyLabelstring"Version history"Accessible name of the group and the menu trigger.

ArtifactActions

The trailing row of icon actions, pushed to the end of the header. Renders a <div>.

ArtifactAction

A muted icon button with its aria-label as tooltip: download, share, close. Forwards Button props.

PropTypeDefaultDescription
aria-labelstring-Required: the name and the tooltip.

ArtifactCopy

An ArtifactAction that writes value to the clipboard and turns its glyph into a check for a moment.

PropTypeDefaultDescription
valuestring | (() => string)-What to copy. Pass a function to read the current version at click time.
copyLabelstring"Copy"Name and tooltip at rest.
copiedLabelstring"Copied"Name and tooltip once copied.

ArtifactTabs

The Preview / Code switch, a segmented Koala TabsList. With it present, ArtifactPreview and ArtifactCode become its panels; without it, both simply render.

PropTypeDefaultDescription
previewLabelReact.ReactNode"Preview"First tab's label.
codeLabelReact.ReactNode"Code"Second tab's label.
childrenReact.ReactNode-Your own TabsTriggers, valued preview and code.

ArtifactContent

The sheet. Keys its children by version: the old version leaves toward where you came from and the new one arrives from where you are going. Renders a <div>.

ArtifactPreview

The live result, scrolling inside the sheet. Renders nothing while generating. Forwards native <div> props.

PropTypeDefaultDescription
srcstring-Render a sandboxed <iframe> at this URL instead of children. It fades in once it loads.
titlestring"Artifact preview"The iframe's accessible title.
sandboxstring"allow-scripts allow-forms allow-popups"The iframe's sandbox flags.

ArtifactCode

The source, as a flat CodeSnippet with line numbers and copy on hover. Renders nothing while generating.

PropTypeDefaultDescription
codestring-The source.
langCodeSnippetProps["lang"]"tsx"Highlighting language.
showLineNumbersbooleantrueShow the gutter.
snippetPropsPartial<CodeSnippetProps>-Anything else for the inner CodeSnippet.

ArtifactEmpty

The pane before anything exists, a compact EmptyState. Forwards EmptyState props; children replace the default parts.

PropTypeDefaultDescription
iconReact.ReactNode<Sparkle />The tile's glyph.
titleReact.ReactNode"Your artifact appears here"The message.
descriptionReact.ReactNode-The line under it.

ArtifactSkeleton

The building state: shimmer lines in the shape of a page, staggered in. Renders only while the pane is generating, with role="status".

PropTypeDefaultDescription
labelstring"Building the artifact"What a screen reader hears.
childrenReact.ReactNode-Your own skeleton, shaped like the artifact you expect.

FAQ#

Because a result is something you work on, and a message is something you read past. A 200-line component in the thread pushes the conversation off the screen and gets copied apart. The card keeps the thread readable and the pane gives the result room, its versions and its code.