SAP Analytics Cloud Custom Widget Development
Table of Contents
Overview
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:
- Building custom visualizations not available in standard SAC
- Integrating third-party charting libraries (ECharts, D3.js, Chart.js)
- Creating interactive input components for SAC applications
- Implementing specialized data displays or KPI widgets
- Extending Analytics Designer applications with custom functionality
- Troubleshooting custom widget loading or data binding issues
Requirements:
- SAC tenant with Optimized Story Experience or Analytics Designer
- JavaScript/Web Components knowledge
- External hosting (GitHub Pages, AWS S3, Azure) OR SAC-hosted resources (QRC Q2 2023+)
Plugin Components
This plugin provides specialized agents, commands, and validation hooks for comprehensive widget development support.
Agents
| 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" |
Commands
| 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 |
/widget-lint |
/widget-lint [file] |
Performance, security, and best practices analysis |
Validation Hooks
Automatic quality checks triggered on Write/Edit operations:
- widget.json: Required fields, tag naming, property types, data binding config
- widget.js: Lifecycle functions, Shadow DOM, propertiesChanged dispatch
- Performance: Resize debouncing, chart disposal, XSS prevention
- Context Reminders: Template suggestions, command recommendations
Templates
Ready-to-use scaffolds in templates/ directory:
basic-widget.js - Minimal Web Component with all lifecycle functions
data-bound-chart.js - ECharts widget with data binding
styling-panel.js - Runtime customization panel
widget.json-minimal - Bare-minimum metadata
widget.json-complete - Full-featured metadata with all options
Quick Start
Minimal Custom Widget Structure
A 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",](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.
Community Sample Widgets
SAP provides 15+ ready-to-use custom widget samples:
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: Optimized View Mode (OVM) enabled, data binding support
Note: Check third-party library licenses before production use.
Key Concepts
Lifecycle Functions
Essential functions called by SAC framework:
onCustomWidgetBeforeUpdate(changedProperties) - Pre-update hook
onCustomWidgetAfterUpdate(changedProperties) - Post-update (render here)
onCustomWidgetResize() - Handle resize events
onCustomWidgetDestroy() - Cleanup resources
Data Binding
Configure 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
this.myDataBinding.data.forEach(row => {
const dimensionValue = row.dimensions_0.label;
const measureValue = row.measures_0.raw;
});
Hosting Options
1. SAC-Hosted (Recommended, QRC Q2 2023+)
- Upload files directly to SAC > Files > Public Files
- Use relative paths:
"/path/to/widget.js"
- Set
"integrity": "" and "ignoreIntegrity": true
2. GitHub Pages
3. External Web Server
- AWS S3, Azure Blob, or any HTTPS server
- Must include CORS headers:
Access-Control-Allow-Origin: *
Security: Integrity Hash
For production, generate SHA256 hash:
# Generate hash
openssl dgst -sha256 -binary widget.js | openssl base64 -A
# Update JSON
"integrity": "sha256-abc123...",
"ignoreIntegrity": false
Common Errors & Solutions
| 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 |
Debugging
Browser DevTools
- Open Chrome DevTools (F12)
- Sources tab: Find widget.js, set breakpoints
- Console tab: View console.log output
- Network tab: Check if files load (200 status)
Debug Pattern
onCustomWidgetAfterUpdate(changedProperties) {
console.log("Widget updated:", changedProperties);
console.log("Current props:", this._props);
console.log("Data binding:", this.myDataBinding?.data);
this._render();
}
Widget Add-Ons (QRC Q4 2023+)
Widget Add-Ons extend built-in SAC widgets without building from scratch.
Use Cases:
- Customize chart tooltips
- Add visual elements to plot areas
- Override built-in styling
Supported Charts: Bar/Column, Stacked Bar/Column, Line, Stacked Area, Numeric Point
Key Differences:
- Only
main and builder components (no styling)
- Must specify extension target (
tooltip, plotArea, numericPoint)
- SAC provides chart context data via methods
See references/widget-addon-guide.md for complete implementation.
Bundled Resources
Templates (Ready-to-Use Code)
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/widget.json-minimal - Bare-minimum metadata (~25 lines)
templates/widget.json-complete - Full-featured metadata (~100 lines)
Reference Documentation
references/json-schema-reference.md - Complete JSON schema documentation
references/widget-templates.md - Additional widget template patterns (6 templates)
references/echarts-integration.md - ECharts library integration guide
references/widget-addon-guide.md - Widget Add-On development (QRC Q4 2023+)
references/best-practices-guide.md - Performance, security, and development guidelines
references/advanced-topics.md - Custom types, script API types, installation
references/integration-and-migration.md - Script integration, content transport
references/script-api-reference.md - DataSource, Selection, MemberInfo APIs
Official Documentation Links
Primary References (for skill updates):
Sample Widgets:
Version History
v2.0.0 (2025-12-27)
- Added 3 specialized agents: widget-architect, widget-debugger, widget-api-assistant
- Added 3 slash commands: /widget-validate, /widget-generate, /widget-lint
- Added validation hooks for automatic quality checks on Write/Edit
- Added 5 production-ready templates in templates/ directory
- Enhanced plugin structure to match comprehensive plugin pattern
- Updated last verified date
v1.2.0 (2025-11-26)
- Updated SAC version reference to 2025.21
- Optimized SKILL.md length from 563 to ~200 lines
- Added Table of Contents to all 8 reference files
- Improved progressive disclosure architecture
v1.1.0 (2025-11-22)
- Added Widget Add-On feature documentation (QRC Q4 2023+)
- Added best practices guide (performance, security, development)
- Added advanced topics (custom types, script API types, installation)
- Enhanced description with additional keywords
- Increased error prevention coverage to 25+
v1.0.0 (2025-11-22)
- Initial release
- Complete JSON metadata reference
- Lifecycle functions documentation
- Data binding guide
- Styling panel implementation
- Hosting options (SAC-hosted, GitHub, external)
- Security (integrity hash, CORS)
- Common errors and debugging
Last Verified: 2025-12-27 | SAC Version: 2025.21 | Skill Version: 2.0.0
1---2name: sap-sac-custom-widget3description: SAP Analytics Cloud (SAC) Custom Widget development skill. Use when building custom visualizations, interactive components, extending SAC with Web Components, or creating Widget Add-Ons to customize built-in widgets. Covers JSON metadata configuration, JavaScript Web Components, lifecycle functions, data binding with feeds, styling panels, builder panels, property/event/method definitions, custom types, script API data types, third-party library integration, hosting options, security, performance optimization, and debugging. Includes Widget Add-On feature (QRC Q4 2023+) for extending built-in widgets without creating from scratch. Provides templates for basic widgets, data-bound charts, styling panels, and KPI cards. Supports Optimized Story Experience and Analytics Designer. Prevents common errors: missing lifecycle functions, incorrect JSON schema, integrity warnings, CORS failures, property type mismatches, data binding issues, and performance anti-patterns. Keywords: sap analytics cloud, sac custom widget4license: GPL-3.05---67# SAP Analytics Cloud Custom Widget Development89## Table of Contents10- [Overview](#overview)11- [Plugin Components](#plugin-components)12- [Quick Start](#quick-start)13- [Community Sample Widgets](#community-sample-widgets)14- [Key Concepts](#key-concepts)15- [Common Errors & Solutions](#common-errors--solutions)16- [Bundled Resources](#bundled-resources)1718## Overview1920This 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.2122**Use this skill when**:23- Building custom visualizations not available in standard SAC24- Integrating third-party charting libraries (ECharts, D3.js, Chart.js)25- Creating interactive input components for SAC applications26- Implementing specialized data displays or KPI widgets27- Extending Analytics Designer applications with custom functionality28- Troubleshooting custom widget loading or data binding issues2930**Requirements**:31- SAC tenant with Optimized Story Experience or Analytics Designer32- JavaScript/Web Components knowledge33- External hosting (GitHub Pages, AWS S3, Azure) OR SAC-hosted resources (QRC Q2 2023+)3435---3637## Plugin Components3839This plugin provides specialized agents, commands, and validation hooks for comprehensive widget development support.4041### Agents4243| Agent | Color | Purpose | Trigger Examples |44|-------|-------|---------|------------------|45| **widget-architect** | Blue | Design widget structure, metadata, and integration patterns | "design custom widget", "plan widget architecture" |46| **widget-debugger** | Yellow | Troubleshoot loading, data binding, CORS, and runtime issues | "widget won't load", "CORS error", "data not binding" |47| **widget-api-assistant** | Green | Write JavaScript widget code, lifecycle functions, API integrations | "write widget code", "implement lifecycle functions" |4849### Commands5051| Command | Usage | Description |52|---------|-------|-------------|53| `/widget-validate` | `/widget-validate [file]` | Validate widget.json schema and widget.js structure |54| `/widget-generate` | `/widget-generate` | Interactively generate widget scaffold with JSON + JS |55| `/widget-lint` | `/widget-lint [file]` | Performance, security, and best practices analysis |5657### Validation Hooks5859Automatic quality checks triggered on Write/Edit operations:60- **widget.json**: Required fields, tag naming, property types, data binding config61- **widget.js**: Lifecycle functions, Shadow DOM, propertiesChanged dispatch62- **Performance**: Resize debouncing, chart disposal, XSS prevention63- **Context Reminders**: Template suggestions, command recommendations6465### Templates6667Ready-to-use scaffolds in `templates/` directory:68- `basic-widget.js` - Minimal Web Component with all lifecycle functions69- `data-bound-chart.js` - ECharts widget with data binding70- `styling-panel.js` - Runtime customization panel71- `widget.json-minimal` - Bare-minimum metadata72- `widget.json-complete` - Full-featured metadata with all options7374---7576## Quick Start7778### Minimal Custom Widget Structure7980A custom widget requires two files:8182**1. widget.json** (Metadata)83```json84{85 "id": "com.company.mywidget",86 "version": "1.0.0",87 "name": "My Custom Widget",88 "description": "A simple custom widget",89 "vendor": "Company Name",90 "license": "MIT",91 "icon": "",92 "webcomponents": [93 {94 "kind": "main",95 "tag": "my-custom-widget",96 "url": "[https://your-host.com/widget.js",](https://your-host.com/widget.js",)97 "integrity": "",98 "ignoreIntegrity": true99 }100 ],101 "properties": {102 "title": {103 "type": "string",104 "default": "My Widget"105 }106 },107 "methods": {},108 "events": {}109}110```111112**2. widget.js** (Web Component)113```javascript114(function() {115 const template = document.createElement("template");116 template.innerHTML = `117 <style>118 :host {119 display: block;120 width: 100%;121 height: 100%;122 }123 .container {124 padding: 16px;125 font-family: Arial, sans-serif;126 }127 </style>128 <div class="container">129 <h3 id="title">My Widget</h3>130 <div id="content"></div>131 </div>132 `;133134 class MyCustomWidget extends HTMLElement {135 constructor() {136 super();137 this._shadowRoot = this.attachShadow({ mode: "open" });138 this._shadowRoot.appendChild(template.content.cloneNode(true));139 this._props = {};140 }141142 connectedCallback() {143 // Called when element is added to DOM144 }145146 onCustomWidgetBeforeUpdate(changedProperties) {147 // Called BEFORE properties are updated148 this._props = { ...this._props, ...changedProperties };149 }150151 onCustomWidgetAfterUpdate(changedProperties) {152 // Called AFTER properties are updated - render here153 if (changedProperties.title !== undefined) {154 this._shadowRoot.getElementById("title").textContent = changedProperties.title;155 }156 }157158 onCustomWidgetResize() {159 // Called when widget is resized160 }161162 onCustomWidgetDestroy() {163 // Cleanup when widget is removed164 }165166 // Property getter/setter (required for SAC framework)167 get title() {168 return this._props.title;169 }170 set title(value) {171 this._props.title = value;172 this.dispatchEvent(new CustomEvent("propertiesChanged", {173 detail: { properties: { title: value } }174 }));175 }176 }177178 customElements.define("my-custom-widget", MyCustomWidget);179})();180```181182**⚠️ Production Note**: The `ignoreIntegrity: true` setting above is **development only**. For production deployments, generate a SHA256 integrity hash and set `ignoreIntegrity: false`.183184---185186## Community Sample Widgets187188SAP provides 15+ ready-to-use custom widget samples:189190**Repository**: [SAP-samples/SAC_Custom_Widgets](https://github.com/SAP-samples/analytics-cloud-datasphere-community-content/tree/main/SAC_Custom_Widgets)191192| Category | Widgets |193|----------|---------|194| **Charts** | Funnel, Pareto, Sankey, Sunburst, Tree, Line, UI5 Gantt |195| **KPI/Gauge** | KPI Ring, Gauge Grade, Half Donut, Nested Pie, Custom Pie |196| **Utilities** | File Upload, Word Cloud, Bar Gradient, Widget Add-on Sample |197198**Requirements**: Optimized View Mode (OVM) enabled, data binding support199200**Note**: Check third-party library licenses before production use.201202---203204## Key Concepts205206### Lifecycle Functions207Essential functions called by SAC framework:208- `onCustomWidgetBeforeUpdate(changedProperties)` - Pre-update hook209- `onCustomWidgetAfterUpdate(changedProperties)` - Post-update (render here)210- `onCustomWidgetResize()` - Handle resize events211- `onCustomWidgetDestroy()` - Cleanup resources212213### Data Binding214Configure in widget.json to receive SAC model data:215```json216{217 "dataBindings": {218 "myDataBinding": {219 "feeds": [220 {221 "id": "dimensions",222 "description": "Dimensions",223 "type": "dimension"224 },225 {226 "id": "measures",227 "description": "Measures",228 "type": "mainStructureMember"229 }230 ]231 }232 }233}234```235236Access data in JavaScript:237```javascript238// Get data binding239const dataBinding = this.dataBindings.getDataBinding("myDataBinding");240241// Access result set242const data = this.myDataBinding.data;243const metadata = this.myDataBinding.metadata;244245// Iterate over rows246this.myDataBinding.data.forEach(row => {247 const dimensionValue = row.dimensions_0.label;248 const measureValue = row.measures_0.raw;249});250```251252### Hosting Options253254**1. SAC-Hosted (Recommended, QRC Q2 2023+)**255- Upload files directly to SAC > Files > Public Files256- Use relative paths: `"/path/to/widget.js"`257- Set `"integrity": ""` and `"ignoreIntegrity": true`258259**2. GitHub Pages**260- Create repository with widget files261- Enable GitHub Pages in Settings262- Use URL: `[https://username.github.io/repo/widget.js`](https://username.github.io/repo/widget.js`)263264**3. External Web Server**265- AWS S3, Azure Blob, or any HTTPS server266- Must include CORS headers: `Access-Control-Allow-Origin: *`267268### Security: Integrity Hash269270For production, generate SHA256 hash:271```bash272# Generate hash273openssl dgst -sha256 -binary widget.js | openssl base64 -A274275# Update JSON276"integrity": "sha256-abc123...",277"ignoreIntegrity": false278```279280---281282## Common Errors & Solutions283284| Error | Cause | Solution |285|-------|-------|----------|286| "The system couldn't load the custom widget" | Incorrect URL or hosting issue | Verify URL is accessible, check CORS |287| "Integrity check failed" | Hash mismatch | Regenerate hash after JS changes |288| Widget not appearing | Missing connectedCallback render | Call render in onCustomWidgetAfterUpdate |289| Properties not updating | Missing propertiesChanged dispatch | Use dispatchEvent with propertiesChanged |290| Data not displaying | Data binding misconfigured | Verify feeds in JSON match usage |291292---293294## Debugging295296### Browser DevTools2971. Open Chrome DevTools (F12)2982. Sources tab: Find widget.js, set breakpoints2993. Console tab: View console.log output3004. Network tab: Check if files load (200 status)301302### Debug Pattern303```javascript304onCustomWidgetAfterUpdate(changedProperties) {305 console.log("Widget updated:", changedProperties);306 console.log("Current props:", this._props);307 console.log("Data binding:", this.myDataBinding?.data);308 this._render();309}310```311312---313314## Widget Add-Ons (QRC Q4 2023+)315316Widget Add-Ons extend built-in SAC widgets without building from scratch.317318**Use Cases**:319- Customize chart tooltips320- Add visual elements to plot areas321- Override built-in styling322323**Supported Charts**: Bar/Column, Stacked Bar/Column, Line, Stacked Area, Numeric Point324325**Key Differences**:326- Only `main` and `builder` components (no `styling`)327- Must specify extension target (`tooltip`, `plotArea`, `numericPoint`)328- SAC provides chart context data via methods329330See **`references/widget-addon-guide.md`** for complete implementation.331332---333334## Bundled Resources335336### Templates (Ready-to-Use Code)337338- **`templates/basic-widget.js`** - Minimal Web Component scaffold (~60 lines)339- **`templates/data-bound-chart.js`** - ECharts widget with SAC data binding (~120 lines)340- **`templates/styling-panel.js`** - Styling panel for runtime customization (~150 lines)341- **`templates/widget.json-minimal`** - Bare-minimum metadata (~25 lines)342- **`templates/widget.json-complete`** - Full-featured metadata (~100 lines)343344### Reference Documentation3453461. **`references/json-schema-reference.md`** - Complete JSON schema documentation3472. **`references/widget-templates.md`** - Additional widget template patterns (6 templates)3483. **`references/echarts-integration.md`** - ECharts library integration guide3494. **`references/widget-addon-guide.md`** - Widget Add-On development (QRC Q4 2023+)3505. **`references/best-practices-guide.md`** - Performance, security, and development guidelines3516. **`references/advanced-topics.md`** - Custom types, script API types, installation3527. **`references/integration-and-migration.md`** - Script integration, content transport3538. **`references/script-api-reference.md`** - DataSource, Selection, MemberInfo APIs354355---356357## Official Documentation Links358359**Primary References** (for skill updates):360- [Custom Widget Developer Guide](https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/0ac8c6754ff84605a4372468d002f2bf/75311f67527c41638ceb89af9cd8af3e.html?version=2025.21&locale=en-US)361- [Developer Guide PDF](https://help.sap.com/doc/c813a28922b54e50bd2a307b099787dc/release/en-US/CustomWidgetDevGuide_en.pdf)362- [Widget API PDF (2025)](https://help.sap.com/doc/7e0efa0e68dc45958e568699f8226ad7/cloud/en-US/SAC_Widget_API_en.pdf)363364**Sample Widgets**:365- [SAP Samples Repository](https://github.com/SAP-samples/analytics-cloud-datasphere-community-content/tree/main/SAC_Custom_Widgets)366- [SAP Custom Widget GitHub](https://github.com/SAP-Custom-Widget)367368---369370## Version History371372**v2.0.0** (2025-12-27)373- Added 3 specialized agents: widget-architect, widget-debugger, widget-api-assistant374- Added 3 slash commands: /widget-validate, /widget-generate, /widget-lint375- Added validation hooks for automatic quality checks on Write/Edit376- Added 5 production-ready templates in templates/ directory377- Enhanced plugin structure to match comprehensive plugin pattern378- Updated last verified date379380**v1.2.0** (2025-11-26)381- Updated SAC version reference to 2025.21382- Optimized SKILL.md length from 563 to ~200 lines383- Added Table of Contents to all 8 reference files384- Improved progressive disclosure architecture385386**v1.1.0** (2025-11-22)387- Added Widget Add-On feature documentation (QRC Q4 2023+)388- Added best practices guide (performance, security, development)389- Added advanced topics (custom types, script API types, installation)390- Enhanced description with additional keywords391- Increased error prevention coverage to 25+392393**v1.0.0** (2025-11-22)394- Initial release395- Complete JSON metadata reference396- Lifecycle functions documentation397- Data binding guide398- Styling panel implementation399- Hosting options (SAC-hosted, GitHub, external)400- Security (integrity hash, CORS)401- Common errors and debugging402403---404405**Last Verified**: 2025-12-27 | **SAC Version**: 2025.21 | **Skill Version**: 2.0.0