mit einem Klick
inline-widget
// Inline HTML widgets: charts, dashboards, data tables rendered directly in the chat via ShowWidget
// Inline HTML widgets: charts, dashboards, data tables rendered directly in the chat via ShowWidget
Manage user profile including watchlists, portfolio, and preferences.
DCF valuation: free cash flow projections, WACC, terminal value, sensitivity analysis
Web scraping with Scrapling: MCP tool wrappers for quick fetching, plus direct Python API for advanced scraping with selectors, sessions, and spiders
Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like "the xlsx in my downloads") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.
Search X (Twitter) posts, pull user profiles, fetch specific tweets, and read reply threads for sentiment, news, and event research. Triggers on 'X', 'Twitter', 'tweets about', 'sentiment on', 'what are people saying about', 'historical tweets', or any request to read public X content.
Report issues and propose fixes to improve your own capabilities when you encounter errors or limitations
| name | inline-widget |
| description | Inline HTML widgets: charts, dashboards, data tables rendered directly in the chat via ShowWidget |
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.
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(html: str, title: str | None = None, data_files: list[str] | None = None)
html: Raw HTML fragment — no <!DOCTYPE>, <html>, <head>, or <body> tagstitle: 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:
cdnjs.cloudflare.com, cdn.jsdelivr.net, unpkg.com, esm.shsendPrompt('text'): global function to trigger follow-up chat messageswindow.__WIDGET_DATA__: dict of filename→content for files passed via data_filesfetch() / 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 HTMLThe widget sits directly on the chat surface inside a transparent iframe. Follow these rules for seamless integration:
The outermost HTML element must have:
background: transparent)<!-- 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 cards, sections, and components should use CSS variables for styling:
/* 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;
position: fixed — breaks iframe auto-sizing (elements collapse to 0 height)position: relative for chart containersThese 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).
Load Chart.js from CDN and follow these rules:
<!-- 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:
responsive: true, maintainAspectRatio: falsewindow.Chart global)getComputedStyle for chart colors-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif)Call sendPrompt('text') from buttons to trigger a follow-up chat message:
<button onclick="sendPrompt('Show detailed revenue breakdown')"
style="padding: 8px 16px; background: var(--color-accent-primary); color: white;
border: none; border-radius: 6px; cursor: pointer;">
Revenue Details ↗
</button>
Add a ↗ arrow on buttons that call sendPrompt() to signal they trigger a chat action.
setInterval and requestAnimationFrame work normally for animations and live tickers:
setInterval(function() {
// Update prices, rotate data, animate
updateDisplay();
}, 3000);
Use data_files to load data from sandbox files instead of inlining everything in the HTML string. This is especially useful for larger datasets.
ShowWidget via data_fileswindow.__WIDGET_DATA__["filename"]# Step 1: Generate data
import json
data = {"labels": ["Q1", "Q2", "Q3"], "values": [100, 150, 200]}
with open("work/<task_name>/chart_data.json", "w") as f:
json.dump(data, f)
# Step 2: Agent calls ShowWidget with data_files
ShowWidget(
html='<div id="chart">...</div><script>var d = JSON.parse(__WIDGET_DATA__["chart_data.json"]); ...</script>',
data_files=["work/<task_name>/chart_data.json"]
)
// Text files (json, csv, txt, etc.) — returned as strings
var data = JSON.parse(window.__WIDGET_DATA__["chart_data.json"]);
var csvText = window.__WIDGET_DATA__["results.csv"];
// Binary files (png, jpg, etc.) — returned as data URLs
document.getElementById("img").src = window.__WIDGET_DATA__["chart.png"];
.json, .csv, .txt, .html, .xml, .svg, .md, .yaml, .yml, .tsv, .geojson, .topojson.png, .jpg, .jpeg, .gif, .webp, .icoTotal inline data is capped at 500KB across all files. Keep datasets concise — aggregate or sample large files before passing them.
The following will cause ShowWidget to reject your HTML with an error. Fix and retry:
| Pattern | Why blocked |
|---|---|
new ResizeObserver(...) | Host handles iframe sizing — your observer creates infinite resize loops |
parent.postMessage(...) | Use sendPrompt() instead — direct postMessage bypasses the bridge |
window.top.* / window.parent.* | Sandboxed iframe — parent access is blocked |
position: fixed | Breaks iframe auto-sizing |
| Background/border on outermost element | Breaks seamless integration with chat surface |
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 16px;">
<div style="background: var(--color-bg-subtle); padding: 14px 16px; border-radius: 8px; border: 0.5px solid var(--color-border-muted);">
<div style="font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px;">Revenue</div>
<div style="font-size: 24px; font-weight: 500;">$2.4M</div>
<div style="font-size: 12px; color: var(--color-profit);">+12.5%</div>
</div>
<!-- more cards... -->
</div>
<table style="width: 100%; border-collapse: collapse; font-size: 14px;">
<thead>
<tr style="border-bottom: 0.5px solid var(--color-border-muted);">
<th style="text-align: left; padding: 8px; color: var(--color-text-secondary); font-weight: 500; font-size: 12px;">Symbol</th>
<th style="text-align: right; padding: 8px; color: var(--color-text-secondary); font-weight: 500; font-size: 12px;">Price</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom: 0.5px solid var(--color-border-muted);">
<td style="padding: 8px; font-weight: 500;">AAPL</td>
<td style="text-align: right; padding: 8px;">$213.18</td>
</tr>
</tbody>
</table>
<div style="background: var(--color-bg-card); border-radius: 8px; border: 0.5px solid var(--color-border-muted); padding: 16px; margin-bottom: 16px;">
<div style="font-size: 16px; font-weight: 500; margin-bottom: 12px;">Performance</div>
<div style="position: relative; height: 200px;">
<canvas id="perfChart"></canvas>
</div>
</div>