Isaiah

BJORK Artifact panel

Component

About

Artifact panel is a production-ready ai component from BJORK UI, packaged for shadcn registries.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds BJORK Artifact panel to your project and fits it to your theme.

Code

How BJORK Artifact panel is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";
import { ThemeProvider as BjorkDemoThemeProvider } from "next-themes";
import { useEffect, useState, type Dispatch, type SetStateAction } from "react";
import { ArtifactPanel, SAMPLE_ARTIFACT, type ArtifactVersion } from "@/components/ui/bjork-artifact-panel";
import { BjorkButton } from "@/components/ui/bjork-artifact-panel-utils/components-bjork-ui-primitives-button";

const BASE = SAMPLE_ARTIFACT.versions[2];

const NEXT_CODE = BASE.code
  .replace(
    '{plan.interval === "year" ? `Billed ${plan.price} yearly` : "Billed monthly"}',
    '{plan.interval === "year" ? `Billed ${plan.price} yearly, save 20%` : "Billed monthly, cancel anytime"}',
  )
  .replace("// Yearly plans show", "// Yearly plans show a savings note and");

const POSED_CHARS = 560;

function Chat({ onOpen, open }: { onOpen: () => void; open: boolean }) {
  return (
    <div className="hidden w-[240px] shrink-0 flex-col gap-3 py-2 font-bjork-alpha @[640px]:flex">
      <div className="self-end rounded-[14px] rounded-br-[6px] bg-[color:var(--bjork-surface-active)] px-3 py-2 text-[13px] leading-5 text-[color:var(--bjork-text)]">
        Make a pricing card for the Studio plan. Yearly should show the monthly price.
      </div>
      <p className="text-[13px] leading-5 text-[color:var(--bjork-text-medium)]">
        Here is a pricing card that takes a plan and shows the monthly equivalent for yearly billing.
      </p>
      <button
        type="button"
        onClick={onOpen}
        aria-pressed={open}
        className="flex h-10 cursor-pointer items-center justify-between gap-2 rounded-[10px] border border-[color:var(--bjork-border)] px-3 text-left text-[13px] font-medium text-[color:var(--bjork-text)] outline-none transition-colors hover:bg-[color:var(--bjork-surface-active)] focus-visible:ring-2 focus-visible:ring-[color:var(--bjork-accent)]"
      >
        Pricing card
        <span className="font-mono text-[10px] uppercase tracking-[0.08em] text-[color:var(--bjork-text-faint)]">
          {open ? "open" : "view"}
        </span>
      </button>
    </div>
  );
}

function Demo({ chars, setChars }: { chars: number | null; setChars: Dispatch<SetStateAction<number | null>> }) {
  const isPreview = false;
  const [open, setOpen] = useState(true);

  useEffect(() => {
    if (isPreview || chars === null || chars >= NEXT_CODE.length) return;
    const id = window.setTimeout(() => setChars((c) => Math.min(NEXT_CODE.length, (c ?? 0) + 9)), 30);
    return () => window.clearTimeout(id);
  }, [isPreview, chars, setChars]);

  const shown = isPreview ? POSED_CHARS : chars;
  const streaming = shown !== null && shown < NEXT_CODE.length;
  const versions: ArtifactVersion[] =
    shown === null
      ? SAMPLE_ARTIFACT.versions
      : [
          ...SAMPLE_ARTIFACT.versions,
          {
            id: "v4",
            code: NEXT_CODE.slice(0, shown),
            language: "tsx",
            createdAt: 1_760_000_400_000,
            preview: streaming ? undefined : BASE.preview,
          },
        ];

  return (
    <div className="flex w-[min(720px,calc(100vw-56px))] flex-col items-stretch gap-5">
      <div className="@container w-full">
        <div className="flex h-[460px] gap-5">
          <Chat open={open} onOpen={() => setOpen(true)} />
          <div className="min-w-0 flex-1">
            {open ? (
              <ArtifactPanel
                title={SAMPLE_ARTIFACT.title}
                kind={SAMPLE_ARTIFACT.kind}
                versions={versions}
                streaming={streaming}
                onClose={() => setOpen(false)}
              />
            ) : (
              <div className="grid h-full place-items-center rounded-[14px] border border-dashed border-[color:var(--bjork-border)]">
                <BjorkButton variant="secondary" size="sm" onClick={() => setOpen(true)}>
                  Open artifact
                </BjorkButton>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
function SourceDemo(){
const [chars, setChars] = useState<number | null>(null);
const streaming = chars !== null && chars < NEXT_CODE.length;
return <>

      <Demo chars={chars} setChars={setChars} />
    
</>;
}
export default function BjorkRegistryPreview(){return <BjorkDemoThemeProvider attribute="class" defaultTheme="dark" enableSystem={false} storageKey="bjork-review-demo-theme"><div data-component-demo className="dark flex min-h-screen w-full items-center justify-center bg-[var(--bjork-bg)] p-8 text-[var(--bjork-text)]"><div className="w-full max-w-[850px]"><SourceDemo/></div></div></BjorkDemoThemeProvider>}

Dependencies

More by Isaiah

View all
  • Agent Plan

    Agent Plan

    2.2K
  • Video Scroll Hero

    Video Scroll Hero

    1.4K
  • Voice Powered Orb

    Voice Powered Orb

    1.3K
  • Reveal Text

    Reveal Text

    1.1K
  • Leads Data Table

    Leads Data Table

    935
  • Portfolio Gallery

    Portfolio Gallery

    923
  • Message Dock

    Message Dock

    833
  • Ruler Carousel

    Ruler Carousel

    619