Widget Components
Overview
Aiffinity owns all consumer-facing UI rendering. Providers describe what to show, not how to show it. Your capability descriptor includes a surfaceGuidance object that tells the widget selector which component types best represent your data. The selector then picks the optimal component based on the user's context, screen real estate, and the 7-dimension budget engine.
Each component type has a budget cost (1–3 units) that the budget engine deducts from the user's per-session attention budget. Lower-cost components are preferred when budget is tight.
stat_row
A single metric display with a label, formatted value, and optional trend indicator. Ideal for KPIs, counts, percentages, or any single data point that benefits from at-a-glance readability.
Example payload
{
"component": "stat_row",
"objective": "inform",
"density": "compact",
"props": {
"label": "Portfolio Value",
"value": "$42,180.00",
"trend": {
"direction": "up",
"delta": "+2.4%",
"period": "24h"
},
"icon": "chart.line.uptrend.xyaxis"
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| label | string | Required | Metric label displayed above or beside the value. |
| value | string | Required | Formatted display value. Provider is responsible for formatting (currency, units, etc.). |
| trend | object | Optional | Trend indicator. Contains direction ("up" | "down" | "flat"), delta (string), and optional period (string). |
| icon | string | Optional | SF Symbol name for a leading icon. Falls back to a default metric icon if omitted. |
| subtitle | string | Optional | Secondary text line below the value. Use for context or comparison. |
sparkline
A miniature line chart for time-series data. Renders 7–30 data points as a smooth curve with optional area fill. Best for showing trends over time without requiring axis labels.
Example payload
{
"component": "sparkline",
"objective": "inform",
"density": "compact",
"props": {
"label": "Steps This Week",
"values": [8420, 6230, 10150, 9800, 7650, 11200, 9400],
"labels": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
"currentValue": "9,400",
"trend": { "direction": "up", "delta": "+12%" },
"color": "green",
"fill": true
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| label | string | Required | Chart title displayed above the sparkline. |
| values | number[] | Required | Array of 7–30 numeric data points. Rendered left-to-right. |
| labels | string[] | Optional | X-axis labels. If provided, must match the length of values. |
| currentValue | string | Optional | Formatted current/latest value displayed alongside the chart. |
| trend | object | Optional | Same trend object as stat_row. Shown next to currentValue. |
| color | string | Optional | Semantic color name: "green", "red", "blue", "orange", "purple". Defaults to "blue". |
| fill | boolean | Optional | Whether to render area fill below the line. Defaults to false. |
progress_bar
A horizontal progress indicator with label, percentage, and optional target. Use for goals, quotas, task completion, or any bounded metric.
Example payload
{
"component": "progress_bar",
"objective": "nudge",
"density": "compact",
"props": {
"label": "Weekly Reading Goal",
"progress": 0.65,
"displayValue": "65%",
"target": "5 books",
"current": "3.25 books",
"color": "orange"
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| label | string | Required | Progress bar label. |
| progress | number | Required | Progress value between 0.0 and 1.0. |
| displayValue | string | Optional | Formatted progress string (e.g., "65%", "3/5"). If omitted, renders progress * 100 as percentage. |
| target | string | Optional | Target description shown beside the bar. |
| current | string | Optional | Current value description. |
| color | string | Optional | Semantic color for the fill. Defaults to "blue". |
ranked_list
An ordered list of items, each with a rank, label, and optional score or badge. Use for leaderboards, top items, recent activity, or any sorted collection.
Example payload
{
"component": "ranked_list",
"objective": "inform",
"density": "standard",
"props": {
"title": "Top Repositories This Week",
"items": [
{ "rank": 1, "label": "aiffinity-core", "value": "142 commits", "badge": "hot" },
{ "rank": 2, "label": "provider-sdk", "value": "87 commits" },
{ "rank": 3, "label": "design-tokens", "value": "54 commits" },
{ "rank": 4, "label": "landing-page", "value": "31 commits" },
{ "rank": 5, "label": "infra-charts", "value": "22 commits" }
],
"maxItems": 5
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| title | string | Required | List heading. |
| items | RankedItem[] | Required | Array of ranked items. Each has rank (number), label (string), optional value (string), optional badge (string), optional imageUrl (string). |
| maxItems | number | Optional | Maximum items to display. Defaults to 5. The renderer may truncate further based on density. |
action_row
A horizontal row of actionable buttons or links. Each action has a label, URL, and optional icon. Use for quick actions, deep links into your service, or contextual shortcuts.
Example payload
{
"component": "action_row",
"objective": "act",
"density": "compact",
"props": {
"actions": [
{
"label": "Open Board",
"url": "https://trello.com/b/abc123",
"icon": "rectangle.stack",
"style": "primary"
},
{
"label": "Create Card",
"url": "https://trello.com/b/abc123/new-card",
"icon": "plus.rectangle",
"style": "secondary"
},
{
"label": "View Activity",
"url": "https://trello.com/b/abc123/activity",
"style": "tertiary"
}
]
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| actions | Action[] | Required | Array of 1–4 actions. Each has label (string, required), url (string, required), optional icon (SF Symbol name), optional style ("primary" | "secondary" | "tertiary"). |
cta_banner
A prominent call-to-action banner with headline, subtitle, and a primary button. Use for onboarding prompts, upgrade offers, feature announcements, or time-sensitive calls to action.
Example payload
{
"component": "cta_banner",
"objective": "act",
"density": "standard",
"props": {
"headline": "Connect Your Calendar",
"subtitle": "Get meeting prep cards, smart scheduling suggestions, and automatic context for every call.",
"button": {
"label": "Connect Google Calendar",
"url": "https://api.aiffinity.me/v1/providers/runtime/auth/google-calendar",
"style": "primary"
},
"dismissible": true,
"icon": "calendar.badge.plus"
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| headline | string | Required | Primary banner text. Keep under 60 characters. |
| subtitle | string | Optional | Supporting text. Keep under 140 characters. |
| button | object | Required | CTA button with label (string), url (string), and optional style ("primary" | "secondary"). |
| dismissible | boolean | Optional | Whether the user can dismiss the banner. Defaults to true. |
| icon | string | Optional | SF Symbol name for a leading icon. |
meeting_prep
A pre-meeting context card that shows attendees, agenda items, relevant notes, and quick-access links. Designed to surface 30–60 minutes before a scheduled event.
Example payload
{
"component": "meeting_prep",
"objective": "prepare",
"density": "expanded",
"props": {
"title": "Weekly Product Sync",
"startsAt": "2026-04-04T14:00:00Z",
"duration": 30,
"location": "Google Meet",
"meetingUrl": "https://meet.google.com/abc-defg-hij",
"attendees": [
{ "name": "Sarah Chen", "role": "Product Lead", "avatarUrl": null },
{ "name": "Marcus Johnson", "role": "Engineering", "avatarUrl": null },
{ "name": "Lisa Park", "role": "Design", "avatarUrl": null }
],
"agenda": [
"Q2 roadmap review",
"Provider SDK beta feedback",
"Widget component catalog status"
],
"notes": "Sarah mentioned wanting to discuss the new onboarding flow. Marcus has a PR ready for the sandbox API.",
"relatedLinks": [
{ "label": "Q2 Roadmap Doc", "url": "https://notion.so/abc123" },
{ "label": "SDK Beta Tracker", "url": "https://linear.app/xyz" }
]
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| title | string | Required | Meeting title from the calendar event. |
| startsAt | string (ISO 8601) | Required | Meeting start time in UTC. |
| duration | number | Optional | Duration in minutes. |
| location | string | Optional | Meeting location or platform name. |
| meetingUrl | string | Optional | Direct join URL. |
| attendees | Attendee[] | Optional | Array of attendees. Each has name (string), optional role (string), optional avatarUrl (string | null). |
| agenda | string[] | Optional | Agenda items as an ordered list of strings. |
| notes | string | Optional | Contextual notes generated from prior interactions and memories. |
| relatedLinks | Link[] | Optional | Related documents or resources. Each has label (string) and url (string). |
compound_card
A multi-section container that composes several sub-components into a single card. Use for rich dashboards, multi-metric summaries, or any scenario where multiple related data points belong together.
Example payload
{
"component": "compound_card",
"objective": "inform",
"density": "expanded",
"props": {
"title": "Shopify Store Overview",
"branding": {
"provider": "Shopify",
"iconUrl": "https://cdn.aiffinity.me/provider-icons/shopify.png",
"accentColor": "#96BF48"
},
"sections": [
{
"component": "stat_row",
"props": {
"label": "Revenue Today",
"value": "$1,842.00",
"trend": { "direction": "up", "delta": "+18%" }
}
},
{
"component": "sparkline",
"props": {
"label": "Orders (7d)",
"values": [12, 18, 15, 22, 19, 28, 24],
"color": "green",
"fill": true
}
},
{
"component": "action_row",
"props": {
"actions": [
{ "label": "View Orders", "url": "https://mystore.myshopify.com/admin/orders", "style": "primary" },
{ "label": "Analytics", "url": "https://mystore.myshopify.com/admin/analytics", "style": "secondary" }
]
}
}
]
}
}
Props
| Property | Type | Required | Description |
|---|---|---|---|
| title | string | Required | Card heading displayed at the top. |
| branding | object | Optional | Provider branding. Contains provider (string), optional iconUrl (string), optional accentColor (hex string). |
| sections | Section[] | Required | Array of 1–4 sub-component sections. Each section has component (a valid component type except compound_card) and props (that component's props). |
Compound Card Structure
The compound_card component nests other components as sections. This is the only component that supports composition. Key rules:
- No nesting: A
compound_cardcannot contain anothercompound_card. - 1–4 sections: The sections array must contain between 1 and 4 entries.
- Section budget: The compound card costs 3 budget units total, regardless of how many sections it contains. Individual section costs are not charged separately.
- Branding: The optional
brandingobject adds a provider icon and accent color to the card header. Use this when the card aggregates data from a single external service. - Layout: Sections render vertically in order. The renderer adds appropriate spacing between sections. You cannot control section layout — Aiffinity determines the optimal arrangement.
// Compound card with branding and 3 sections
{
"component": "compound_card",
"props": {
"title": "GitHub Activity",
"branding": {
"provider": "GitHub",
"iconUrl": "https://cdn.aiffinity.me/provider-icons/github.png"
},
"sections": [
{ "component": "stat_row", "props": { "label": "Open PRs", "value": "7" } },
{ "component": "stat_row", "props": { "label": "Issues Assigned", "value": "12" } },
{ "component": "action_row", "props": { "actions": [{ "label": "Open GitHub", "url": "https://github.com", "style": "primary" }] } }
]
}
}
Budget Engine
The Aiffinity widget selector uses a 7-dimension budget system to control the density and cognitive load of widgets shown to each user. Every session starts with a budget allocation across all seven dimensions. Each widget consumes budget based on its component type and objective.
Visual
Screen real estate and visual complexity. Charts and expanded cards cost more than compact stat rows.
Cognitive
Mental processing load. Dense data tables and multi-metric cards require more cognitive effort.
Action
Decision pressure. CTAs and action rows ask the user to do something, consuming action budget.
Temporal
Time sensitivity. Meeting prep and time-bound alerts are penalized if shown at the wrong time.
Novelty
Information freshness. Repeated or stale widgets are deprioritized. New data gets a novelty bonus.
Social
Social interaction load. Widgets involving other people (meeting prep, shared content) draw from this pool.
Ambient
Background awareness. Low-urgency ambient context (weather, portfolio, step count) shares this budget.
Component budget costs
| Component | Cost | Primary Dimensions |
|---|---|---|
| stat_row | 1 | Visual (low), Cognitive (low) |
| sparkline | 2 | Visual (medium), Cognitive (medium) |
| progress_bar | 1 | Visual (low), Cognitive (low), Action (low) |
| ranked_list | 2 | Visual (medium), Cognitive (medium) |
| action_row | 2 | Action (high), Cognitive (low) |
| cta_banner | 3 | Visual (high), Action (high), Cognitive (medium) |
| meeting_prep | 3 | Visual (high), Cognitive (high), Social (high), Temporal (high) |
| compound_card | 3 | Visual (high), Cognitive (high) |
Surface Guidance
Your capability descriptor includes a surfaceGuidance object that tells the widget selector how to render your data. The selector uses this guidance alongside the budget engine and user context to choose the optimal component and placement.
{
"surfaceGuidance": {
"intent": "ambient_context",
"placement": ["home_widgets", "daily_brief"],
"components": ["stat_row", "sparkline"]
}
}
Fields
| Field | Type | Description |
|---|---|---|
| intent | string | The purpose of this widget. One of: "ambient_context", "active_task", "social_context", "time_sensitive", "milestone", "call_to_action". |
| placement | string[] | Where this widget can appear. Options: "home_widgets", "daily_brief", "aiffinity_screen", "chat_context", "notification". |
| components | string[] | Preferred component types, in order of preference. The selector picks the first component that fits within the current budget. |
The components array should list your preferred types in descending order of richness. For example, ["compound_card", "sparkline", "stat_row"] tells the selector to try a compound card first, fall back to a sparkline if budget is tight, and use a stat row as a last resort.