Skip to main content
ClaudeWave
Skill1.4k repo starsupdated today

inline-widget

The inline-widget skill renders interactive HTML/SVG visualizations directly within chat conversations using the ShowWidget function, displaying charts, data tables, dashboards, and metric cards without requiring external sandboxes or preview URLs. Use this when users need quick, self-contained visualizations with embedded data and interactive elements like buttons or animated graphics, rather than complex multi-page applications that require server-side functionality.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/ginlix-ai/LangAlpha /tmp/inline-widget && cp -r /tmp/inline-widget/skills/inline-widget ~/.claude/skills/inline-widget
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Inline Widget

Render interactive HTML/SVG widgets directly inside the chat conversation using `ShowWidget`. Widgets appear inline between text — no sandbox, no preview URL, no side panel.

## When to Use

- User wants a **quick visualization** embedded in the conversation (chart, metric card, data table)
- The visualization is **self-contained** — all data is embedded in the HTML, no server needed
- User wants **interactivity** within the chat: buttons, toggles, hover effects, animated charts
- The output is a **single view** — not a multi-page app or dashboard that needs routing

**Use `interactive-dashboard` instead if:** User needs a multi-page web app, server-side data, live data refresh, or complex interactivity requiring React/FastAPI.

## ShowWidget API

```
ShowWidget(html: str, title: str | None = None, data_files: list[str] | None = None)
```

- `html`: Raw HTML fragment — no `<!DOCTYPE>`, `<html>`, `<head>`, or `<body>` tags
- `title`: Optional metadata (not displayed to user)
- `data_files`: Optional list of sandbox file paths to make available as `window.__WIDGET_DATA__`

The HTML is rendered in a sandboxed iframe with:
- **CDN libraries**: `cdnjs.cloudflare.com`, `cdn.jsdelivr.net`, `unpkg.com`, `esm.sh`
- **CSS theme variables**: automatically injected (see Theme section)
- **`sendPrompt('text')`**: global function to trigger follow-up chat messages
- **`window.__WIDGET_DATA__`**: dict of filename→content for files passed via `data_files`
- **No network to non-CDN origins**: `fetch()` / `XMLHttpRequest` to arbitrary URLs are blocked by CSP — only CDN domains (cdnjs, jsdelivr, unpkg, esm.sh) are allowed. Use `data_files` for sandbox files, or embed small data directly in HTML

## Layout Rules (CRITICAL)

The widget sits directly on the chat surface inside a transparent iframe. Follow these rules for seamless integration:

### Outer Element — Transparent Shell

The **outermost HTML element** must have:
- **NO background** (or `background: transparent`)
- **NO border**
- **NO border-radius**
- **NO box-shadow**
- **NO padding** — add padding on inner sections only

```html
<!-- CORRECT: transparent outer shell -->
<div>
  <div style="background: var(--color-bg-card); border-radius: 8px; padding: 16px; ...">
    ...inner card content...
  </div>
</div>

<!-- WRONG: styled outer wrapper — will be rejected -->
<div style="background: var(--color-bg-page); border: 1px solid ...; border-radius: 8px; padding: 20px;">
  ...content...
</div>
```

### Inner Elements — Use Theme Variables

Inner cards, sections, and components should use CSS variables for styling:

```css
/* Card */
background: var(--color-bg-card);
border: 0.5px solid var(--color-border-muted);
border-radius: 8px;
padding: 16px;

/* Metric card */
background: var(--color-bg-subtle);
border: 0.5px solid var(--color-border-muted);
border-radius: 8px;
```

### Positioning

- **NO `position: fixed`** — breaks iframe auto-sizing (elements collapse to 0 height)
- Use `position: relative` for chart containers
- No nested scrolling — the iframe auto-sizes to fit all content

## Theme Variables

These CSS variables are automatically injected and resolve correctly in both light and dark mode:

| Variable | Purpose |
|----------|---------|
| `--color-bg-page` | Page background |
| `--color-bg-card` | Card/panel background |
| `--color-bg-elevated` | Elevated surface |
| `--color-bg-subtle` | Subtle/muted background |
| `--color-bg-hover` | Hover state background |
| `--color-text-primary` | Primary text |
| `--color-text-secondary` | Secondary/muted text |
| `--color-text-tertiary` | Hint/label text |
| `--color-border-muted` | Default border (use with 0.5px) |
| `--color-accent-primary` | Brand/accent color |
| `--color-profit` | Positive/gain (green) |
| `--color-loss` | Negative/loss (red) |
| `--color-warning` | Warning (amber) |
| `--color-info` | Info (blue) |
| `--color-success` | Success (green) |

**Never hardcode colors** like `#333` or `rgb(...)` for text, backgrounds, or borders — they break in dark mode. Use CSS variables for everything except chart canvas colors (Chart.js canvas cannot read CSS variables — use computed hex values via `getComputedStyle`).

## Charts (Chart.js)

Load Chart.js from CDN and follow these rules:

```html
<!-- Wrapper div with explicit height — REQUIRED -->
<div style="position: relative; height: 200px;">
  <canvas id="myChart"></canvas>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
  // Read CSS variables for chart colors (canvas can't use var())
  var cs = getComputedStyle(document.documentElement);
  var accent = cs.getPropertyValue('--color-accent-primary').trim();
  var border = cs.getPropertyValue('--color-border-muted').trim();

  new Chart(document.getElementById('myChart'), {
    type: 'line',
    data: {
      labels: [...],
      datasets: [{
        data: [...],
        borderColor: accent,
        backgroundColor: accent + '20',
        tension: 0.4,
        fill: true
      }]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,  // REQUIRED
      plugins: { legend: { display: true } },
      scales: {
        y: { grid: { color: border } },
        x: { grid: { display: false } }
      }
    }
  });
</script>
```

**Key rules:**
- Set height on the **wrapper div**, never on the canvas
- Always use `responsive: true, maintainAspectRatio: false`
- Use UMD build from CDN (sets `window.Chart` global)
- Read CSS variables via `getComputedStyle` for chart colors

## Typography

- Font: inherited from host (`-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif`)
- Weight: **400** (regular) and **500** (medium) only — never 600 or 700
- Heading sizes: h1 = 22px, h2 = 18px, h3 = 16px (all weight 500)
- Body: 14-16px, weight 400
- Use **sentence case** — no Title Case or ALL CAPS (except short metric labels)

## Interactivity

### sendPrompt()

Call `sendPrompt('text')` from buttons to trigger a follow-up chat messa