Generative UI Skill
This skill contains the complete design system for Claude's built-in show_widget tool โ the generative UI feature that renders interactive HTML/SVG widgets inline in claude.ai conversations. The guidelines below are the actual Anthropic "Imagine โ Visual Creation Suite" design rules, extracted so you can produce high-quality widgets directly without needing the read_me setup call.
How it works: On claude.ai, Claude has access to the show_widget tool which renders raw HTML/SVG fragments inline in the conversation. This skill provides the design system, templates, and patterns to use it well.
Step 1: Pick the Right Visual Type
Route on the verb, not the noun. Same subject, different visual depending on what was asked:
| User says |
Type |
Format |
| "how does X work" |
Illustrative diagram |
SVG |
| "X architecture" |
Structural diagram |
SVG |
| "what are the steps" |
Flowchart |
SVG |
| "explain compound interest" |
Interactive explainer |
HTML |
| "compare these options" |
Comparison grid |
HTML |
| "show revenue chart" |
Chart.js chart |
HTML |
| "create a contact card" |
Data record |
HTML |
| "draw a sunset" |
Art/illustration |
SVG |
Step 2: Build the Widget
Structure (strict order)
<style> โ HTML content โ <script>
Output streams token-by-token. Styles must exist before the elements they target, and scripts must run after the DOM is ready.
Philosophy
- Seamless: Users shouldn't notice where the host UI ends and your widget begins
- Flat: No gradients, mesh backgrounds, noise textures, or decorative effects. Clean flat surfaces
- Compact: Show the essential inline. Explain the rest in text
- Text goes in your response, visuals go in the tool โ all explanatory text, descriptions, and summaries must be written as normal response text OUTSIDE the tool call. The tool output should contain ONLY the visual element
Core Rules
- No
<!-- comments --> or /* comments */ (waste tokens, break streaming)
- No font-size below 11px
- No emoji โ use CSS shapes or SVG paths
- No gradients, drop shadows, blur, glow, or neon effects
- No dark/colored backgrounds on outer containers (transparent only โ host provides the bg)
- Typography: two weights only: 400 regular, 500 medium. Never use 600 or 700. Headings: h1=22px, h2=18px, h3=16px โ all font-weight 500. Body text=16px, weight 400, line-height 1.7
- Sentence case always. Never Title Case, never ALL CAPS
- No mid-sentence bolding โ entity names go in
code style not bold
- No
<!DOCTYPE>, <html>, <head>, or <body> โ just content fragments
- No
position: fixed โ use normal-flow layouts
- No tabs, carousels, or
display: none sections during streaming
- No nested scrolling โ auto-fit height
- Corners:
border-radius: var(--border-radius-lg) for cards, var(--border-radius-md) for elements
- No rounded corners on single-sided borders (border-left, border-top)
- Round every displayed number โ use
Math.round(), .toFixed(n), or Intl.NumberFormat
CDN Allowlist (CSP-enforced)
External resources may ONLY load from:
cdnjs.cloudflare.com
cdn.jsdelivr.net
unpkg.com
esm.sh
All other origins are blocked โ the request silently fails.
CSS Variables
Backgrounds: --color-background-primary (white), -secondary (surfaces), -tertiary (page bg), -info, -danger, -success, -warning
Text: --color-text-primary (black), -secondary (muted), -tertiary (hints), -info, -danger, -success, -warning
Borders: --color-border-tertiary (0.15ฮฑ, default), -secondary (0.3ฮฑ, hover), -primary (0.4ฮฑ), semantic -info/-danger/-success/-warning
Typography: --font-sans, --font-serif, --font-mono
Layout: --border-radius-md (8px), --border-radius-lg (12px), --border-radius-xl (16px)
All auto-adapt to light/dark mode.
Dark mode is mandatory โ every color must work in both modes:
- In HTML: always use CSS variables for text. Never hardcode colors like
color: #333
- In SVG: use pre-built color classes (
c-blue, c-teal, etc.) โ they handle light/dark automatically
- Mental test: if the background were near-black, would every text element still be readable?
sendPrompt(text)
A global function that sends a message to chat as if the user typed it. Use it when the user's next step benefits from Claude thinking. Handle filtering, sorting, toggling, and calculations in JS instead.
Step 3: Render with show_widget
The show_widget tool is built into claude.ai โ no activation needed. Pass your widget code directly:
{
"title": "snake_case_widget_name",
"widget_code": "<style>...</style>\n<div>...</div>\n<script>...</script>"
}
| Parameter |
Type |
Required |
Description |
title |
string |
Yes |
Snake_case identifier for the widget |
widget_code |
string |
Yes |
HTML or SVG code. For SVG: start with <svg>. For HTML: content fragment |
For SVG output: start widget_code with <svg โ it will be auto-detected and wrapped appropriately.
Step 4: Chart.js Template
For charts, use onload callback pattern to handle script load ordering:
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px;">
<div style="background: var(--color-background-secondary); border-radius: var(--border-radius-md); padding: 1rem;">
<div style="font-size: 13px; color: var(--color-text-secondary);">Label</div>
<div style="font-size: 24px; font-weight: 500;" id="stat1">โ</div>
</div>
</div>
<div style="position: relative; width: 100%; height: 300px; margin-top: 1rem;">
<canvas id="myChart"></canvas>
</div>
<div style="display: flex; align-items: center; gap: 12px; margin-top: 1rem;">
<label style="font-size: 14px; color: var(--color-text-secondary);">Parameter</label>
<input type="range" min="0" max="100" value="50" id="param" step="1" style="flex: 1;" />
<span style="font-size: 14px; font-weight: 500; min-width: 32px;" id="param-out">50</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js" onload="initChart()"></script>
<script>
function initChart() {
const slider = document.getElementById('param');
const out = document.getElementById('param-out');
let chart = null;