🎨

Web Artifacts Builder

Verified

by Anthropic

Anthropic's pattern for producing complex interactive HTML artifacts — single-file React apps with state, routing, and shadcn/ui components. Outputs a self-contained .html file that runs in any browser via CDN imports. Use for dashboards, calculators, mini-apps, and explorable data viz.

htmlreacttailwindshadcnartifactuiprototypeanthropic
View on GitHub

Web Artifacts Builder

Produce single-file HTML artifacts that run in any browser without a build step. Adapted from Anthropic's web-artifacts-builder skill.

When to use

  • Dashboards or data viz the user wants to interact with.
  • Calculators, converters, mini-tools.
  • Explorable explanations (component playground, charting demo).
  • Interactive mockups for prototyping UI ideas.

When NOT to use

  • Static text-only output → use markdown or HTML directly.
  • Anything that needs a backend or persistent storage → use a real Next.js / Express setup.
  • Anything > 1500 lines → split into a real project.

Template

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>{{Title}}</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body class="bg-zinc-50">
  <div id="root"></div>
  <script type="text/babel" data-presets="react,env">
    const { useState, useEffect, useMemo } = React

    function App() {
      const [count, setCount] = useState(0)
      return (
        <div className="max-w-2xl mx-auto p-8">
          <h1 className="text-3xl font-bold mb-4">Hello</h1>
          <button
            className="px-4 py-2 rounded bg-zinc-900 text-white hover:bg-zinc-700"
            onClick={() => setCount(c => c + 1)}
          >
            Clicked {count}
          </button>
        </div>
      )
    }

    ReactDOM.createRoot(document.getElementById('root')).render(<App />)
  </script>
</body>
</html>

Adding shadcn-style components

For shadcn/ui, port the Tailwind class patterns directly — don't try to import the package (no build step). Common patterns:

// Button
<button className="inline-flex items-center justify-center rounded-md text-sm font-medium
  bg-zinc-900 text-zinc-50 hover:bg-zinc-900/90 h-10 px-4 py-2">Click</button>

// Card
<div className="rounded-lg border bg-white text-zinc-950 shadow-sm">
  <div className="p-6">...</div>
</div>

// Input
<input className="flex h-10 w-full rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm
  focus:outline-none focus:ring-2 focus:ring-zinc-950" />

Charting / 3rd party libs

Load from CDN inside <head>:

  • Charts: https://unpkg.com/recharts/umd/Recharts.js
  • Icons: https://unpkg.com/lucide@latest/dist/umd/lucide.js
  • Math: https://unpkg.com/mathjs@latest/lib/browser/math.js

Best practices

  • One file. No imports of local files. Everything CDN or inline.
  • Use Tailwind utility classes — no custom CSS unless absolutely needed.
  • Keep state minimal. If it gets complex, add useReducer.
  • Test by opening the file in a browser before delivering.
  • Add a viewport meta tag for mobile.

Output

Write the HTML to a file (e.g. /tmp/artifact.html) so the user can open it locally, or paste it inline if the chat UI renders HTML artifacts.