Widget Composition Reference
This is the canonical authoring reference for building new dashboard widgets. Use it when deciding:- which recipe to start from
- which layout node to use for structure
- which section primitive to use for each surface
- whether a new need should become a recipe, primitive, or just composition
packages/widgets/src/templates/composition-catalog.ts
Authoring Order
Always design widgets in this order:- What is the top-level spatial grammar?
- What are the major buckets?
- Which section primitives render each bucket?
- Does the complexity live in a nested bucket layout or in a missing primitive?
- Add a new recipe only when the top-level spatial grammar changes.
- Add a new primitive when the behavior or visual shell inside a bucket is reusable.
- Use nested layout nodes when the variation is structural inside a bucket.
- Do not create a recipe just to name a domain-specific widget pattern.
Canonical Recipes
These are the canonical top-level recipes. New widgets should start from one of these.summary_only
Use when:
- the widget is primarily a compact metric surface
- there is no primary list, table, or chart body
- the whole point is a set of summary cards or KPI rows
- compact revenue summary
- compact sponsorship summary
- small health or status summaries
summary-quadkpi-rowheadline-statoverview-panel
- the widget has a main content body the user is expected to scan
content_only
Use when:
- the widget is one primary content surface
- there is no meaningful summary bucket
- the content body may itself contain a nested
stack,grid, ortabs
- logs
- bookmark lists
- changelog feeds
- single-surface task or note lists
listrow-liststream-listtable- nested
tabs - nested
grid
- top-level summary metrics are part of the main value
summary_content
Use when:
- there is a real summary bucket
- the main body is not just one canonical list surface
- the content bucket may contain multiple sections or nested layouts
- stars with metrics plus charts plus table
- health views with metrics plus tabbed content
- tasks with stats plus active work list
- summary:
headline-stat,kpi-row,summary-quad,overview-panel - content:
chart,table,row-list, nestedtabs, nestedgrid
- the body is just one primary list and no extra composition is needed
summary_list
Use when:
- there is a summary bucket
- the body is one primary list-like surface
- analytics compact
- SEO compact
- downloads
- notes
- RSS widget
- status page widget
- summary:
headline-stat,kpi-row - content:
list,row-list,table
summary_chart_list
Use when:
- the body clearly wants both a chart and a list
- chart + list are both first-class, not optional embellishments
- compact analytical widgets with one trend chart plus one ranked list
- summary:
headline-stat,kpi-row - content:
chartthenlistortable
rail_content
Use when:
- the left side is a narrow context/overview rail
- the right side is the main scanning or interaction surface
- review pulse
- future “profile + activity” widgets
- context-heavy widgets where metadata belongs in a side rail
- rail:
overview-panel,headline-stat,summary-quad - content:
row-list,table, nestedtabs, nestedgrid
rail_list
Use when:
- the left side is compact context
- the right side is one primary list/feed/table
- sentry mode in observability
- rail:
headline-stat,chart,overview-panel - content:
row-list,list,table
Layout Nodes
Layout nodes define structure only.stack
Use when:
- sections should read vertically in a single flow
- order matters more than side-by-side comparison
- summary-only layouts
- content-only layouts
- simple grouped content
grid
Use when:
- a bucket needs parallel surfaces of equal or near-equal importance
- two to four sub-panels should coexist in the same region
- multi-chart content buckets
- paired metric blocks
- nested content composition inside
summary_contentorcontent_only
tabs
Use when:
- the content modes are mutually exclusive
- the user only needs one content view visible at a time
- alternate content modes
- switching between lists/tables/charts without vertical sprawl
split
Use when:
- the layout is explicitly a left rail plus a main pane
rail_contentrail_list
- top-level
splitis allowed - nested
splitis intentionally disallowed in v1
Section Primitives
These are the current reusable visual/behavioral building blocks.Summary / Context
headline-stat
Use for one strong metric with a label and optional status color.
Best for:
- live visitors
- unresolved issue count
- one dominant KPI
kpi-row
Use for 1-6 compact comparable metrics.
Best for:
- compact metric strips
- “supporting KPIs” under a larger summary
summary-quad
Use for a 2x2 summary shell with richer metric cards.
Best for:
- revenue and sponsorship-style summary surfaces
- change
- sparkline
- breakdown
- footer metadata
overview-panel
Use for a narrow contextual rail or hero summary block.
Best for:
- title + primary metric + status badge + descriptive copy + metadata rows
- review pulse
- future “entity profile” side rails
headline-stat when the panel is narrative and metadata-rich.
Lists / Tables / Feeds
list
Use for lighter-weight stacked or inline lists.
Best for:
- top pages
- package lists
- simple compact ranked items
row-list
Use for two-line rows with status/badge/value/timestamp support.
Best for:
- issues
- tasks
- notes
- status items
- review rows
row-list.
stream-list
Use for live or chronological event feeds.
Best for:
- logs
- event streams
- append-heavy activity surfaces
row-list when live behavior, level filters, or stream semantics matter.
dense-ranked-table
Use for compact analytical ranking tables with richer column variants.
Best for:
- keyword rankings
- dense metric comparisons
- bars
- rank deltas
- flag cells
- compact analytical scanning
table
Use for generic expanded tables.
Best for:
- sortable, searchable tabular datasets
- expanded analytical/detail views
card-list
Use for image-forward card grids with richer metadata.
Best for:
- bookmarks
- gallery-like content
- visual collections
- image cards
- grid scanning
- optional search
- richer meta fields than a simple list row
Controls / Visualization / State
filter-bar
Use for explicit persisted controls above a dense content surface.
Best for:
- select/range/toggle-driven filtering
- analytical widgets where the controls are part of the widget contract
chart
Use for single-series or straightforward chart views.
Best for:
- line, area, bar, sparkline content
activity-chart
Use for segmented bucket activity visualizations.
Best for:
- health/deploy status buckets
- discrete activity categories over time
alert
Use for setup, warning, error, or conditional info messaging.
Best for:
- stale data warnings
- setup hints
- conditional state callouts
tabs
Use as a section primitive when the rendered tab control itself is part of the content surface.
Best for:
- content mode switching with counts, icons, or accent styling
Current Missing Or Candidate Primitives
These are the main candidates that still look plausible. They are not automatically required.trend-panel
Status:
- proposed in the earlier standardization spec
- not implemented in the current primitive catalog
- one compact metric
- one small sparkline or micro-chart
- one small footer/meta block
overview-panel plus chart, or by summary-quad.
detail-table
Status:
- proposed in the earlier standardization spec
- not implemented as a distinct primitive
- shared header/footer framing
- shared filter/footer shell
- consistent detail-mode container behavior beyond generic
table
table plus recipe composition still covers most cases.
rich-content
Status:
- not implemented
- widgets that want markdown or richer narrative text blocks instead of list/table structures
What We Are Not Missing
These should stay composition, not become new recipes:- “analytics widget recipe”
- “review widget recipe”
- “task widget recipe”
- “sponsorship widget recipe”
LLM Authoring Heuristics
When composing a new widget, ask these questions in order.1. Is the widget mostly metrics, mostly content, or a split rail + content surface?
Choose:- mostly metrics:
summary_only - mostly one content body:
content_only - metrics + body:
summary_contentorsummary_list - context rail + body:
rail_contentorrail_list
2. Is the body one primary list/table, or multiple co-equal surfaces?
Choose:- one list/table/feed:
summary_list,rail_list, orcontent_only - multiple surfaces:
summary_contentorrail_content - chart + list specifically:
summary_chart_list
3. Does the complexity live inside the body?
If yes:- keep the same top-level recipe
- use nested
stack,grid, ortabsinside thecontentorrailbucket
4. Is a current primitive clearly wrong for the content?
If yes:- add a primitive only if the behavior will be reused
- otherwise compose existing primitives instead
Practical Defaults
If unsure, prefer:summary_listfor compact analytical widgetscontent_onlyfor feeds or simple content widgetsrow-listoverlistwhen rows need richer metadatatablefor expanded detail viewsoverview-panelfor narrative or metadata-rich side rails