generative-ui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Generative UI Skill

生成式UI技能

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.

本技能包含Claude内置
show_widget
工具的完整设计系统——该生成式UI功能可在claude.ai对话中内联渲染交互式HTML/SVG组件。以下指南是Anthropic官方的「Imagine — 视觉创作套件」设计规则,提取后可让你直接生成高质量组件,无需先调用
read_me
进行设置。
工作原理:在claude.ai平台上,Claude可访问
show_widget
工具,该工具能在对话中内联渲染原始HTML/SVG片段。本技能提供了使用该工具的设计系统、模板和模式。

Step 1: Pick the Right Visual Type

步骤1:选择合适的视觉类型

Route on the verb, not the noun. Same subject, different visual depending on what was asked:
User saysTypeFormat
"how does X work"Illustrative diagramSVG
"X architecture"Structural diagramSVG
"what are the steps"FlowchartSVG
"explain compound interest"Interactive explainerHTML
"compare these options"Comparison gridHTML
"show revenue chart"Chart.js chartHTML
"create a contact card"Data recordHTML
"draw a sunset"Art/illustrationSVG

根据动词而非名词来选择。同一主题,根据用户的提问方式选择不同的视觉类型:
用户提问类型格式
"X的工作原理是什么"说明性图表SVG
"X的架构"结构图表SVG
"步骤有哪些"流程图SVG
"解释复利"交互式讲解器HTML
"对比这些选项"对比表格HTML
"展示收入图表"Chart.js图表HTML
"创建联系卡片"数据记录HTML
"画日落"艺术插画SVG

Step 2: Build the Widget

步骤2:构建组件

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.
<style>  →  HTML内容  →  <script>
输出是逐token流式传输的。样式必须在其目标元素之前定义,脚本必须在DOM准备完成后运行。

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
  • 无缝衔接:用户不应注意到宿主UI和组件的边界
  • 扁平化:无渐变、网格背景、噪点纹理或装饰效果,采用简洁的平面设计
  • 紧凑性:仅展示核心内容,其余说明用文本补充
  • 文本在响应中,视觉在工具中——所有解释性文本、描述和摘要必须作为普通响应文本写在工具调用之外。工具输出应仅包含视觉元素

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
  • 禁止使用
    <!-- comments -->
    /* comments */
    (浪费token,破坏流式传输)
  • 字体大小不得小于11px
  • 禁止使用emoji——改用CSS形状或SVG路径
  • 禁止使用渐变、阴影、模糊、发光或霓虹效果
  • 外部容器不得使用深色/彩色背景(仅透明——由宿主提供背景)
  • 排版:仅使用两种字重:400常规、500中等。绝不要使用600或700。标题:h1=22px,h2=18px,h3=16px——全部为font-weight 500。正文字体=16px,字重400,行高1.7
  • 始终使用句子大小写。绝不要使用标题大小写或全大写
  • 句中禁止加粗——实体名称使用
    代码样式
    而非加粗
  • 禁止使用
    <!DOCTYPE>
    <html>
    <head>
    <body>
    ——仅使用内容片段
  • 禁止使用
    position: fixed
    ——使用正常流布局
  • 流式传输期间禁止使用标签页、轮播或
    display: none
    区域
  • 禁止嵌套滚动——自动适配高度
  • 圆角:卡片使用
    border-radius: var(--border-radius-lg)
    ,元素使用
    var(--border-radius-md)
  • 单边边框(border-left、border-top)禁止使用圆角
  • 所有显示的数字必须四舍五入——使用
    Math.round()
    .toFixed(n)
    Intl.NumberFormat

CDN Allowlist (CSP-enforced)

CDN白名单(受CSP限制)

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.
外部资源仅可从以下地址加载:
  • cdnjs.cloudflare.com
  • cdn.jsdelivr.net
  • unpkg.com
  • esm.sh
所有其他源均被阻止——请求会静默失败。

CSS Variables

CSS变量

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?
背景色
--color-background-primary
(白色)、
-secondary
(表面色)、
-tertiary
(页面背景)、
-info
-danger
-success
-warning
文本色
--color-text-primary
(黑色)、
-secondary
(弱化色)、
-tertiary
(提示色)、
-info
-danger
-success
-warning
边框色
--color-border-tertiary
(透明度0.15,默认)、
-secondary
(透明度0.3, hover状态)、
-primary
(透明度0.4)、语义化的
-info/-danger/-success/-warning
字体
--font-sans
--font-serif
--font-mono
布局
--border-radius-md
(8px)、
--border-radius-lg
(12px)、
--border-radius-xl
(16px)
所有变量会自动适配亮色/暗色模式。
暗色模式是强制要求——每种颜色必须在两种模式下都可用:
  • 在HTML中:始终使用CSS变量设置文本颜色。绝不要硬编码颜色如
    color: #333
  • 在SVG中:使用预定义的颜色类(
    c-blue
    c-teal
    等)——它们会自动适配亮色/暗色模式
  • 测试方法:如果背景接近黑色,所有文本元素是否仍清晰可读?

sendPrompt(text)

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.

一个全局函数,可模拟用户输入向聊天发送消息。当用户的下一步操作需要Claude进一步思考时使用。过滤、排序、切换和计算逻辑应在JS中处理。

Step 3: Render with
show_widget

步骤3:使用
show_widget
渲染

The
show_widget
tool is built into claude.ai — no activation needed. Pass your widget code directly:
json
{
  "title": "snake_case_widget_name",
  "widget_code": "<style>...</style>\n<div>...</div>\n<script>...</script>"
}
ParameterTypeRequiredDescription
title
stringYesSnake_case identifier for the widget
widget_code
stringYesHTML 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.

show_widget
工具内置在claude.ai中——无需激活。直接传入组件代码即可:
json
{
  "title": "snake_case_widget_name",
  "widget_code": "<style>...</style>\n<div>...</div>\n<script>...</script>"
}
参数类型是否必填描述
title
字符串组件的蛇形命名标识符
widget_code
字符串HTML或SVG代码。SVG需以
<svg>
开头;HTML需为内容片段
对于SVG输出:
widget_code
需以
<svg
开头——会被自动检测并适当包裹。

Step 4: Chart.js Template

步骤4:Chart.js模板

For charts, use
onload
callback pattern to handle script load ordering:
html
<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;

  function update() {
    const val = parseFloat(slider.value);
    out.textContent = val;
    document.getElementById('stat1').textContent = val.toFixed(1);

    const labels = [], data = [];
    for (let x = 0; x <= 100; x++) {
      labels.push(x);
      data.push(x * val / 100);
    }

    if (chart) chart.destroy();
    chart = new Chart(document.getElementById('myChart'), {
      type: 'line',
      data: { labels, datasets: [{ data, borderColor: '#7F77DD', borderWidth: 2, pointRadius: 0, fill: false }] },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { display: false } },
        scales: { x: { grid: { display: false } } }
      }
    });
  }

  slider.addEventListener('input', update);
  update();
}
if (window.Chart) initChart();
</script>
Chart.js rules:
  • Canvas cannot resolve CSS variables — use hardcoded hex
  • Set height ONLY on the wrapper div, never on canvas itself
  • Always
    responsive: true, maintainAspectRatio: false
  • Always disable default legend, build custom HTML legends
  • Number formatting:
    -$5M
    not
    $-5M
    (negative sign before currency symbol)
  • Use
    onload="initChart()"
    on CDN script tag +
    if (window.Chart) initChart();
    as fallback

对于图表,使用
onload
回调模式处理脚本加载顺序:
html
<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;

  function update() {
    const val = parseFloat(slider.value);
    out.textContent = val;
    document.getElementById('stat1').textContent = val.toFixed(1);

    const labels = [], data = [];
    for (let x = 0; x <= 100; x++) {
      labels.push(x);
      data.push(x * val / 100);
    }

    if (chart) chart.destroy();
    chart = new Chart(document.getElementById('myChart'), {
      type: 'line',
      data: { labels, datasets: [{ data, borderColor: '#7F77DD', borderWidth: 2, pointRadius: 0, fill: false }] },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { display: false } },
        scales: { x: { grid: { display: false } } }
      }
    });
  }

  slider.addEventListener('input', update);
  update();
}
if (window.Chart) initChart();
</script>
Chart.js规则:
  • Canvas无法解析CSS变量——使用硬编码的十六进制颜色
  • 仅在包裹div上设置高度,绝不要在canvas本身上设置
  • 始终设置
    responsive: true, maintainAspectRatio: false
  • 始终禁用默认图例,使用自定义HTML图例
  • 数字格式:
    -$5M
    而非
    $-5M
    (负号在货币符号之前)
  • 在CDN脚本标签上使用
    onload="initChart()"
    ,并添加
    if (window.Chart) initChart();
    作为回退

Step 5: SVG Diagram Template

步骤5:SVG图表模板

For flowcharts and diagrams, use SVG with pre-built classes:
svg
<svg width="100%" viewBox="0 0 680 H">
  <defs>
    <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </marker>
  </defs>

  <!-- Single-line node (44px tall) -->
  <g class="node c-blue" onclick="sendPrompt('Tell me more about this')">
    <rect x="250" y="40" width="180" height="44" rx="8" stroke-width="0.5"/>
    <text class="th" x="340" y="62" text-anchor="middle" dominant-baseline="central">Step one</text>
  </g>

  <!-- Connector arrow -->
  <line x1="340" y1="84" x2="340" y2="120" class="arr" marker-end="url(#arrow)"/>

  <!-- Two-line node (56px tall) -->
  <g class="node c-teal" onclick="sendPrompt('Explain this step')">
    <rect x="230" y="120" width="220" height="56" rx="8" stroke-width="0.5"/>
    <text class="th" x="340" y="140" text-anchor="middle" dominant-baseline="central">Step two</text>
    <text class="ts" x="340" y="158" text-anchor="middle" dominant-baseline="central">Processes the input</text>
  </g>
</svg>
SVG rules:
  • ViewBox always 680px wide (
    viewBox="0 0 680 H"
    ). Set H to fit content + 40px padding
  • Safe area: x=40 to x=640, y=40 to y=(H-40)
  • Pre-built classes:
    t
    (14px),
    ts
    (12px secondary),
    th
    (14px medium 500),
    box
    ,
    node
    ,
    arr
    ,
    c-{color}
  • Every
    <text>
    element must carry a class (
    t
    ,
    ts
    , or
    th
    )
  • Use
    dominant-baseline="central"
    for vertical text centering in boxes
  • Connector paths need
    fill="none"
    (SVG defaults to
    fill: black
    )
  • Stroke width: 0.5px for borders and edges
  • Make all nodes clickable:
    onclick="sendPrompt('...')"

对于流程图和图表,使用带有预定义类的SVG:
svg
<svg width="100%" viewBox="0 0 680 H">
  <defs>
    <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </marker>
  </defs>

  <!-- 单行节点(高44px) -->
  <g class="node c-blue" onclick="sendPrompt('Tell me more about this')">
    <rect x="250" y="40" width="180" height="44" rx="8" stroke-width="0.5"/>
    <text class="th" x="340" y="62" text-anchor="middle" dominant-baseline="central">Step one</text>
  </g>

  <!-- 连接线箭头 -->
  <line x1="340" y1="84" x2="340" y2="120" class="arr" marker-end="url(#arrow)"/>

  <!-- 双行节点(高56px) -->
  <g class="node c-teal" onclick="sendPrompt('Explain this step')">
    <rect x="230" y="120" width="220" height="56" rx="8" stroke-width="0.5"/>
    <text class="th" x="340" y="140" text-anchor="middle" dominant-baseline="central">Step two</text>
    <text class="ts" x="340" y="158" text-anchor="middle" dominant-baseline="central">Processes the input</text>
  </g>
</svg>
SVG规则:
  • ViewBox宽度固定为680px(
    viewBox="0 0 680 H"
    )。设置H以适配内容并添加40px内边距
  • 安全区域:x=40至x=640,y=40至y=(H-40)
  • 预定义类:
    t
    (14px)、
    ts
    (12px次要文本)、
    th
    (14px中等字重500)、
    box
    node
    arr
    c-{color}
  • 每个
    <text>
    元素必须携带类(
    t
    ts
    th
  • 盒子内垂直居中文本使用
    dominant-baseline="central"
  • 连接线需设置
    fill="none"
    (SVG默认
    fill: black
  • 边框和线条的描边宽度:0.5px
  • 所有节点需可点击:
    onclick="sendPrompt('...')"

Step 6: Interactive Explainer Template

步骤6:交互式讲解器模板

For interactive explainers (sliders, live calculations, inline SVG):
html
<div style="display: flex; align-items: center; gap: 12px; margin: 0 0 1.5rem;">
  <label style="font-size: 14px; color: var(--color-text-secondary);">Years</label>
  <input type="range" min="1" max="40" value="20" id="years" style="flex: 1;" />
  <span style="font-size: 14px; font-weight: 500; min-width: 24px;" id="years-out">20</span>
</div>

<div style="display: flex; align-items: baseline; gap: 8px; margin: 0 0 1.5rem;">
  <span style="font-size: 14px; color: var(--color-text-secondary);">$1,000 →</span>
  <span style="font-size: 24px; font-weight: 500;" id="result">$3,870</span>
</div>

<div style="margin: 2rem 0; position: relative; height: 240px;">
  <canvas id="chart"></canvas>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js" onload="initChart()"></script>
<script>
function initChart() {
  // slider logic, chart rendering, sendPrompt() for follow-ups
}
if (window.Chart) initChart();
</script>
Use
sendPrompt()
to let users ask follow-ups:
sendPrompt('What if I increase the rate to 10%?')

对于交互式讲解器(滑块、实时计算、内联SVG):
html
<div style="display: flex; align-items: center; gap: 12px; margin: 0 0 1.5rem;">
  <label style="font-size: 14px; color: var(--color-text-secondary);">Years</label>
  <input type="range" min="1" max="40" value="20" id="years" style="flex: 1;" />
  <span style="font-size: 14px; font-weight: 500; min-width: 24px;" id="years-out">20</span>
</div>

<div style="display: flex; align-items: baseline; gap: 8px; margin: 0 0 1.5rem;">
  <span style="font-size: 14px; color: var(--color-text-secondary);">$1,000 →</span>
  <span style="font-size: 24px; font-weight: 500;" id="result">$3,870</span>
</div>

<div style="margin: 2rem 0; position: relative; height: 240px;">
  <canvas id="chart"></canvas>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js" onload="initChart()"></script>
<script>
function initChart() {
  // 滑块逻辑、图表渲染、使用sendPrompt()处理后续问题
}
if (window.Chart) initChart();
</script>
使用
sendPrompt()
让用户发起后续提问:
sendPrompt('What if I increase the rate to 10%?')

Step 7: Respond to the User

步骤7:响应用户

After rendering the widget, briefly explain:
  1. What the widget shows
  2. How to interact with it (which controls do what)
  3. One key insight from the data
Keep it concise — the widget speaks for itself.

渲染组件后,简要说明:
  1. 组件展示的内容
  2. 如何与组件交互(各个控件的功能)
  3. 数据中的一个关键洞察
保持简洁——组件本身已说明大部分内容。

Reference Files

参考文件

  • references/design_system.md
    — Complete color palette (9 ramps × 7 stops), CSS variables, UI component patterns, metric cards, layout rules
  • references/svg_and_diagrams.md
    — SVG viewBox setup, font calibration, pre-built classes, flowchart/structural/illustrative diagram patterns with examples
  • references/chart_js.md
    — Chart.js configuration, script load ordering, canvas sizing, legend patterns, dashboard layout
Read the relevant reference file when you need specific design tokens, SVG coordinate math, or Chart.js configuration details.
  • references/design_system.md
    — 完整调色板(9个色系×7个色阶)、CSS变量、UI组件模式、指标卡片、布局规则
  • references/svg_and_diagrams.md
    — SVG ViewBox设置、字体校准、预定义类、流程图/结构图/说明图的模式及示例
  • references/chart_js.md
    — Chart.js配置、脚本加载顺序、Canvas尺寸、图例模式、仪表板布局
当你需要特定的设计标记、SVG坐标计算或Chart.js配置细节时,阅读相关参考文件。