plugins/sap-sac-custom-widget/skills/sap-sac-custom-widget/SKILL.md
SAP Analytics Cloud (SAC) Custom Widget development. Use when building custom visualizations, extending SAC with Web Components, or creating Widget Add-Ons. Covers JSON metadata, JavaScript Web Components, lifecycle functions, data binding with feeds, styling/builder panels, property/event/method definitions, third-party library integration, hosting, security, performance, and debugging. Includes Widget Add-On feature (QRC Q4 2023+) and templates for widgets, charts, and KPI cards.
npx skillsauth add secondsky/sap-skills sap-sac-custom-widgetInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill enables development of custom widgets for SAP Analytics Cloud (SAC). Custom widgets are Web Components that extend SAC stories and applications with custom visualizations, interactive elements, and specialized functionality.
Use this skill when:
Requirements:
For prompt-driven widget creation, first classify the widget role and data-source mode, then suggest 2-3 role-aware options before generating the selected complete package. Keep AI-generated code SAC-compatible, preserve data-binding order when used, and validate/repair before import. See references/ai-assisted-composite-generation.md for output contracts, RAG context patterns, brand styling, and composite caveats.
Before generating a table, chart, KPI, menu, sidebar, filter, or hybrid control, select both its widget role and data-source mode. Request dimensions, measures/key figures, dates, versions, filters, and feed order only for SAC-bound widgets. For pure UI controls, collect interaction, navigation, state, method/event, accessibility, and responsive-layout requirements instead. Accept user-provided screenshots, PDFs, images, brand guides, and sanitized data as evidence, but confirm technical IDs, feed mappings, asset rights, and licenses before code generation. See references/widget-discovery-intake.md for the Widget Brief, evidence boundaries, and hosted-tool safeguards.
For enterprise or locked-down local environments, offer templates/local-builder/ as the standard no-install scaffold builder. It runs as static HTML/CSS/vanilla JavaScript, avoids public CDNs and external packages, and exports SAC upload artifacts as two separate downloads: widget.json and a Resource-ZIP containing only root-level component JavaScript files. Use Node's server.mjs fallback when direct file:// use is blocked. When a user explicitly permits public-web use for a non-sensitive desktop prototype, optionally suggest the Custom Widget Builder or live demo; never send tenant material or trust its exports without local validation. See references/local-builder-workflow.md for builder boundaries, export rules, hosted-tool safeguards, and validation checks.
Before generating a chart, KPI, hierarchy, input utility, Widget Add-On, or build-based widget, consult references/sap-sample-widget-lessons.md. It audits every SAP sample folder and distills reusable lessons for Data Binding-first scaffolds, root-relative Resource-ZIP URLs, styling/builder panel separation, support flags, custom types, script methods/events, add-on extensions[], and build-based app caveats. Use the lessons for structure and risk checks only; do not copy SAP sample code or assets into generated packages.
Generated widget packages should include templates/design-runtime/ as a no-build, file-first browser preview scaffold. Use it after generation to mock custom-widget essentials outside SAP, adjust properties/design tokens/sample data/viewports, compare multiple widgets, and export an agent iteration payload. See references/browser-design-runtime.md for runtime boundaries and configuration/export contracts. Use templates/local-builder/ for scaffold generation/export; use templates/design-runtime/ for preview and iteration.
Style custom widgets inside their Web Component/Shadow DOM boundary. Do not rely on SAC optimized story theme CSS, SAP shell selectors, or global story CSS to style widget internals. For generated packages, confirm the hosting mode before splitting CSS/HTML into separate files, because SAC ZIP upload packages support component JavaScript and PNG/JPG icons only. See references/css-and-styling-compliance.md for SAP Help-backed allowed/restricted styling rules.
Decide the delivery mode before generating widget.json: SAC Resource-ZIP upload and external HTTPS hosting use different URL rules. For SAC Resource-ZIP upload, deliver widget.json separately, upload it first, and only then upload a Resource-ZIP containing root-level component JavaScript files such as widget.js, builder.js, and styling.js. Do not include widget.json, subfolders, tests, README files, CSS, or HTML in that Resource-ZIP.
For Resource-ZIP manifests, use root-relative component URLs such as "/widget.js"; for external hosting, use complete HTTPS URLs. Keep local-preview paths like "widget.js" in preview-only configs unless the target SAC flow explicitly documents that resolution mode. Model simple configurable colors as string properties with hex defaults such as "#f4f7fa"; use the Color type only after the exact SAC tenant and target panel flow accepts it. Browser preview and Node tests are useful, but they are not proof of SAC importability. For widgets with builder/styling panels, preserve focus and collapse state during text edits, keep component JS self-contained, and validate final outputs/ artifacts rather than source-only previews. When the widget is done, the final chat response must offer both completed upload artifacts for download: the widget.json manifest and the Resource-ZIP. See references/sac-import-packaging-lessons.md for upload sequence, ZIP content checks, final-artifact tests, builder/tree rules, final download handoff, and SAC error triage.
This plugin provides specialized agents, commands, and validation hooks for comprehensive widget development support.
| Agent | Color | Purpose | Trigger Examples | |-------|-------|---------|------------------| | widget-architect | Blue | Design widget structure, metadata, and integration patterns | "design custom widget", "plan widget architecture" | | widget-debugger | Yellow | Troubleshoot loading, data binding, CORS, and runtime issues | "widget won't load", "CORS error", "data not binding" | | widget-api-assistant | Green | Write JavaScript widget code, lifecycle functions, API integrations | "write widget code", "implement lifecycle functions" |
| Command | Usage | Description |
|---------|-------|-------------|
| /widget-validate | /widget-validate [file] | Validate widget.json schema and widget.js structure |
| /widget-generate | /widget-generate | Interactively generate widget scaffold with JSON, JS, local builder, and browser design runtime |
| /widget-lint | /widget-lint [file] | Performance, security, and best practices analysis |
Automatic quality checks triggered on Write/Edit operations:
Ready-to-use scaffolds in templates/ directory:
basic-widget.js - Minimal Web Component with all lifecycle functionsdata-bound-chart.js - ECharts widget with data bindingstyling-panel.js - Runtime customization panelbuilder-panel.js - Design-time configuration panellocal-builder/ - Static local scaffold builder and SAC artifact exporterdesign-runtime/ - Browser preview and design iteration runtimewidget.json-minimal - Bare-minimum metadatawidget.json-complete - Full-featured metadata with all optionsA custom widget requires two files:
1. widget.json (Metadata)
{
"id": "com.company.mywidget",
"version": "1.0.0",
"name": "My Custom Widget",
"description": "A simple custom widget",
"vendor": "Company Name",
"license": "MIT",
"icon": "",
"webcomponents": [
{
"kind": "main",
"tag": "my-custom-widget",
"url": "https://your-host.com/widget.js",
"integrity": "",
"ignoreIntegrity": true
}
],
"properties": {
"title": {
"type": "string",
"default": "My Widget"
}
},
"methods": {},
"events": {}
}
2. widget.js (Web Component)
(function() {
const template = document.createElement("template");
template.innerHTML = `
<style>
:host {
display: block;
width: 100%;
height: 100%;
}
.container {
padding: 16px;
font-family: Arial, sans-serif;
}
</style>
<div class="container">
<h3 id="title">My Widget</h3>
<div id="content"></div>
</div>
`;
class MyCustomWidget extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({ mode: "open" });
this._shadowRoot.appendChild(template.content.cloneNode(true));
this._props = {};
}
connectedCallback() {
// Called when element is added to DOM
}
onCustomWidgetBeforeUpdate(changedProperties) {
// Called BEFORE properties are updated
this._props = { ...this._props, ...changedProperties };
}
onCustomWidgetAfterUpdate(changedProperties) {
// Called AFTER properties are updated - render here
if (changedProperties.title !== undefined) {
this._shadowRoot.getElementById("title").textContent = changedProperties.title;
}
}
onCustomWidgetResize() {
// Called when widget is resized
}
onCustomWidgetDestroy() {
// Cleanup when widget is removed
}
// Property getter/setter (required for SAC framework)
get title() {
return this._props.title;
}
set title(value) {
this._props.title = value;
this.dispatchEvent(new CustomEvent("propertiesChanged", {
detail: { properties: { title: value } }
}));
}
}
customElements.define("my-custom-widget", MyCustomWidget);
})();
⚠️ Production Note: The ignoreIntegrity: true setting above is development only. For production deployments, generate a SHA256 integrity hash and set ignoreIntegrity: false.
SAP provides a community sample repository with 17 custom widget sample folders:
Repository: SAP-samples/SAC_Custom_Widgets
| Category | Widgets | |----------|---------| | Charts | Funnel, Pareto, Sankey, Sunburst, Tree, Line, UI5 Gantt | | KPI/Gauge | KPI Ring, Gauge Grade, Half Donut, Nested Pie, Custom Pie | | Utilities | File Upload, Word Cloud, Bar Gradient, Widget Add-on Sample |
Requirements: Most samples assume Data Binding and Optimized View Mode (OVM) or Optimized and Unified Story Experience.
Note: Check third-party library licenses before production use, adjust hosted component paths when moving samples, and treat live SAC import/runtime validation as tenant-specific. See references/sap-sample-widget-lessons.md for the per-sample audit and creation lessons.
Essential functions called by SAC framework:
onCustomWidgetBeforeUpdate(changedProperties) - Pre-update hookonCustomWidgetAfterUpdate(changedProperties) - Post-update (render here)onCustomWidgetResize() - Handle resize eventsonCustomWidgetDestroy() - Cleanup resourcesConfigure in widget.json to receive SAC model data:
{
"dataBindings": {
"myDataBinding": {
"feeds": [
{
"id": "dimensions",
"description": "Dimensions",
"type": "dimension"
},
{
"id": "measures",
"description": "Measures",
"type": "mainStructureMember"
}
]
}
}
}
Access data in JavaScript:
// Get data binding
const dataBinding = this.dataBindings.getDataBinding("myDataBinding");
// Access result set
const data = this.myDataBinding.data;
const metadata = this.myDataBinding.metadata;
// Iterate over rows
for (let i = 0; i < this.myDataBinding.data.length; i++) {
const row = this.myDataBinding.data[i];
const dimensionValue = row.dimensions_0 ? row.dimensions_0.label : "";
const measureValue = row.measures_0 ? row.measures_0.raw : 0;
}
1. SAC-Hosted (Recommended, QRC Q2 2023+)
widget.json first, then upload a separate Resource-ZIP when SAC enables the Resource File button"/widget.js"; do not use local Windows backslashes or bare local preview paths in the production manifest"integrity": "" and "ignoreIntegrity": true2. GitHub Pages
https://username.github.io/repo/widget.js3. External Web Server
Access-Control-Allow-Origin: *For production, generate a SHA256 integrity value with Node.js for Windows/macOS/Linux:
# Generate integrity hash for widget.js
node -e "const fs=require('node:fs');const crypto=require('node:crypto');const file=process.argv[1]||'widget.js';console.log('sha256-'+crypto.createHash('sha256').update(fs.readFileSync(file)).digest('base64'));" widget.js
# Update JSON
"integrity": "sha256-abc123...",
"ignoreIntegrity": false
On macOS/Linux or Git Bash, OpenSSL is also acceptable; prefix the output with sha256- before adding it to the manifest:
openssl dgst -sha256 -binary widget.js | openssl base64 -A
| Error | Cause | Solution |
|-------|-------|----------|
| "The system couldn't load the custom widget" | Incorrect URL or hosting issue | Verify URL is accessible, check CORS |
| "Integrity check failed" | Hash mismatch | Regenerate hash after JS changes |
| Widget not appearing | Missing connectedCallback render | Call render in onCustomWidgetAfterUpdate |
| Properties not updating | Missing propertiesChanged dispatch | Use dispatchEvent with propertiesChanged |
| Data not displaying | Data binding misconfigured | Verify feeds in JSON match usage |
| "Color" is not a valid type or default expected as Color | Tenant/import flow rejected simple color properties | Use string plus hex defaults for simple configurable colors |
| Main component could not be loaded | Resource URL, ZIP content, or JS syntax problem | Check root-relative webcomponents[].url, Resource-ZIP root contents, then node --check |
| Resource File upload is disabled | widget.json has not validated yet | Upload and validate widget.json first, then upload the Resource-ZIP |
| Resource-ZIP imports/later load fails | ZIP contains manifest, folders, CSS/HTML, or unrelated files | Keep only root-level JS component files and optional PNG/JPG icons |
| Builder input loses focus or collapse state | Text edits trigger full render | Update field/row/JSON text directly; reserve full render for structural changes |
| Preview works but SAC component fails standalone | Preview depends on a shared source helper not present in bundled JS | Test final widget.js, builder.js, and styling.js without preview-only helper scripts |
| Duplicate menu items collide | Subtree duplicate rewrote only root ID | Rewrite descendant IDs and test uniqueness across the whole tree |
onCustomWidgetAfterUpdate(changedProperties) {
console.log("Widget updated:", changedProperties);
console.log("Current props:", this._props);
console.log("Data binding:", this.myDataBinding && this.myDataBinding.data);
this._render();
}
Widget Add-Ons extend built-in SAC widgets without building from scratch.
Use Cases:
Supported Charts: Bar/Column, Stacked Bar/Column, Line, Stacked Area, Numeric Point
Key Differences:
main and builder components (no styling)tooltip, plotArea, numericPoint)See references/widget-addon-guide.md for complete implementation.
templates/basic-widget.js - Minimal Web Component scaffold (~60 lines)templates/data-bound-chart.js - ECharts widget with SAC data binding (~120 lines)templates/styling-panel.js - Styling panel for runtime customization (~150 lines)templates/builder-panel.js - Builder panel for design-time configurationtemplates/local-builder/ - No-install local builder for metadata, feeds, properties, methods, events, and SAC two-file exporttemplates/design-runtime/ - No-build browser preview, design-token controls, scenario switching, and agent iteration exporttemplates/widget.json-minimal - Bare-minimum metadata (~25 lines)templates/widget.json-complete - Full-featured metadata (~100 lines)references/json-schema-reference.md - Complete JSON schema documentationreferences/widget-templates.md - Additional widget template patterns (6 templates)references/echarts-integration.md - ECharts library integration guidereferences/widget-addon-guide.md - Widget Add-On development (QRC Q4 2023+)references/best-practices-guide.md - Performance, security, and development guidelinesreferences/advanced-topics.md - Custom types, script API types, installationreferences/integration-and-migration.md - Script integration, content transportreferences/script-api-reference.md - DataSource, Selection, MemberInfo APIsreferences/ai-assisted-composite-generation.md - Prompt-driven generation, RAG, brand styling, validation, and composite-ready output guidancereferences/local-builder-workflow.md - Enterprise-safe local builder workflow, export contract, and validation checklistreferences/sap-sample-widget-lessons.md - SAP sample widget audit matrix, reusable generation lessons, and add-on/build-based routing caveatsreferences/browser-design-runtime.md - Non-SAP browser preview runtime, sidecar config, and agent iteration exportreferences/css-and-styling-compliance.md - SAP Help-backed CSS, theme, Shadow DOM, and packaging guidance for generated widgetsreferences/sac-import-packaging-lessons.md - SAC-hosted Resource-ZIP upload sequence, URL rules, ZIP hygiene, builder/tree state rules, self-contained component checks, final-artifact tests, and SAC error triagereferences/widget-discovery-intake.md - Widget role/data-source selection, attachment intake, Widget Brief, and hosted-tool safeguardsPrimary References (for skill updates):
Sample Widgets:
Unreleased
templates/local-builder/ scaffold for local widget metadata, property/feed configuration, and SAC two-file artifact exporttemplates/builder-panel.js so builder panel generation has a bundled self-contained templatelast_verified; live SAC upload/runtime validation remains pendingv2.3.2 (2026-07-06)
widget.json and Resource-ZIP upload flow, root-relative SAC-hosted URLs, Resource-ZIP content hygiene, and simple color property portabilityColor property usagewidget.json manifest and Resource-ZIP as separate downloadable artifactsv2.1.0 (2026-06-12)
eula, imports, supportsMobile, supportsExport, supportsLinkedAnalysisFilterOnSelection, supportsViewportLoading, supportsBookmark, typestype property for ES module loadingincludeInBookmarks per-property flag, boolean[]/integer[] typesserializeCustomWidgetToImage() and customWidgetRenderComplete to advanced topicsv2.0.0 (2025-12-27)
v1.2.0 (2025-11-26)
v1.1.0 (2025-11-22)
v1.0.0 (2025-11-22)
SAC Version: 2026.8
tools
Use when automating SAP BW query inspection, InfoProvider metadata reads (characteristics, key figures), metadata-verified specification review, unsaved draft preparation, or human-confirmed query draft population through Eclipse or HANA Studio with BW Modeling Tools.
tools
Use when an agent must inspect or operate an authenticated SAP web UI through an in-app Browser, Microsoft Edge CDP, or an existing Playwright client, especially when SAP SSO reuse, isolated Edge profiles, deterministic target selection, screenshots, or browser bootstrap recovery is required.
tools
Evidence-based assessment of whether an SAP API/interface usage scenario aligns with the SAP API Policy (v.4.2026a). Use whenever someone asks whether a way of calling SAP is allowed/compliant — e.g. Published API vs internal/private/"confidential" API status, "Documented Use", whether a third-party tool / iPaaS / middleware / RPA bot / AI agent / MCP server may call SAP APIs, agentic or generative-AI access to SAP, bulk data extraction or replication into a lake/warehouse, custom Z/Y OData or RFC/BAPI wrappers and Clean Core, ADT/developer-tooling boundaries, ODP-RFC and other "not permitted" interfaces, partner Integration Certification, or RISE integration remediation. Trigger even when the policy is not named, e.g. "are we allowed to…", "is it compliant to…", "can we connect X to SAP…", "will this break under the new API policy". Produces a sourced technical assessment with a confidence level — explicitly NOT legal advice and NOT a final SAP compliance decision.
development
SAP-RPT-1-OSS local tabular prediction workflows for FI/CO prototype datasets. Use when preparing SAP finance CSV exports for classification or regression experiments with source-verified setup, leakage checks, and governance review.