Dashboard Widget Development
Hub for building, packaging, and publishing SveltyCMS dashboard widgets โ self-contained marketplace-portable packages.
On this page
The admin Dashboard is a widget-based grid. Each widget is a self-contained package living in its own kebab-case folder under src/routes/(app)/dashboard/widgets/<folder>/. Packages are discovered at build time by Vite import.meta.glob โ no manual registration, no runtime filesystem scans.
Core commerce packages (freemium, 14-day trial): Commerce Orders (commerce-orders) and Commerce Inventory (commerce-inventory). They read the optional ecommerce preset collections and stay empty on a non-store CMS. Catalog data can be imported with Smart Importer (WooCommerce / Shopify). Product map: E-Commerce Overview.
๐ Documentation Map
| Guide | Description |
|---|---|
| Architecture | Folder structure, widget.json manifest, registry, and licensing. |
| Development | Step-by-step guide to building your own dashboard widget. |
| Marketplace | Publishing dashboard widgets to marketplace.sveltycms.com. |
๐๏ธ Package Layout (1 folder = 1 widget)
Every dashboard widget must ship a co-located .mdx file that describes the widget โ the marketplace uses it for the package listing card and detail page:
src/routes/(app)/dashboard/widgets/
system-health/
index.svelte # Entry component (fixed name)
widget.json # Marketplace manifest (required)
readme.mdx # Marketplace description (REQUIRED, fixed name)
logs/
index.svelte
widget.json
readme.mdx
commerce-orders/ # freemium, 14-day trial
index.svelte
widget.json
readme.mdx
- Folder โ kebab-case package id (
system-health,logs,last5-content). - Component โ always
index.svelte. The folder id is the registry key saved in user layouts, so renaming the implementation file never breaks saved dashboards. widget.jsonโ machine-readable metadata for the marketplace, the in-app catalog, and telemetry.<component>.mdxโ human-readable marketplace description: features, licensing, data source, and metadata. Required for every package.
๐ How Discovery Works
| Layer | Mechanism |
|---|---|
| Client registry | +page.svelte โ optional widgets; picker from page data; Svelte chunk only when added / visible |
| Server widget picker | +page.server.ts โ widget.json via getInstalledDashboardWidgets() (no Svelte eval) |
| Saved layout | Hydrated in load() from system.preferences; client skips /api/system-preferences on first paint |
| Manifest registry | manifest-registry.ts โ import.meta.glob("./*/widget.json") |
| Telemetry | Reports installed package ids via the manifest registry |
| Marketplace catalog | Local packages appear in GET /api/marketplace (offline-first merge) |
Drop a new folder into widgets/, restart the dev server, and the widget appears in the picker โ the same flow a marketplace install uses.
๐งช Testing Policy
- Shell tests (
tests/unit/routes/dashboard-page-server.test.ts) assert the registry shape, never a fixed widget list โ the catalog is install-specific. - Runtime helpers (
tests/unit/dashboard/dashboard-runtime.test.ts) cover picker mapping, CMS-range filtering, layout unwrap, and hidden-tab poll gating. - Widget defaults are unit-tested in
tests/unit/dashboard/widget-defaults.test.ts. - Per-widget tests live in the widgetโs own folder (
widgets/<folder>/tests/) โ optional but encouraged for marketplace submissions.