Multi-Input Visuals
Combine data from multiple cards into composite visualizations
Multi-input visuals combine data from multiple card tabs into a single composite visualization. A KPI header paired with a trend chart. A comparison view with multiple metrics side by side. A dashboard widget that aggregates insights from different queries.
This guide covers everything you need to build multi-input custom visuals.
When to Use Multi-Input Visuals
Multi-input visuals solve problems that single queries cannot:
| Use Case | Example | Why Multi-Input |
|---|---|---|
| KPI + Trend | Revenue headline with monthly sparkline | KPI needs aggregation, trend needs time series |
| Metric Comparison | Current vs. previous period side by side | Different date filters per dataset |
| Dashboard Widgets | Hero KPI with supporting metrics grid | Different card types composed together |
| Multi-Series Charts | Multiple data sources overlaid | Independent queries that share a visualization |
If your visual needs data from a single query, use a single-input visual instead.
Mental Model: Slots and Tabs
Multi-input visuals use a slot system where each slot maps to a tab in the editor.
Key concepts:
- The config card is the tab that stores the custom visual preferences (URL, component, settings).
By default it starts as slot 0 when tabs are auto-created, but it can move if users reorder tabs. - Slot 1+ are input cards. Each provides data to the composite visual.
- The
dataprop is positional:data[0]is tab 0’s query results,data[1]is tab 1’s results, and so on. - Each slot can have its own settings via
slotSettings, metadata viacardMetadata, and effective card type.
When users add your multi-input visual to a dashboard, Semaphor auto-creates tabs based on your slot definitions.
Tutorial: Build a KPI + Trend Chart
Let's build a practical example: a KPI header with a multi-series area chart below it.
Step 1: Define Slots in the Manifest
In components.config.ts, declare your visual as multi-input with slot definitions:
Step 2: Handle the Data Array
Your component receives data as an array of datasets:
Step 3: Access Per-Slot Card Metadata
Each slot has metadata including title, card type, and formatting configuration:
Step 4: Global Settings vs. Slot Settings
Settings are split between global (applies to entire visual) and per-slot:
Step 5: Provide Slot Guidance
Slot definitions help users understand what each tab expects. When they select your visual, Semaphor:
- Auto-creates tabs matching your
slotsarray - Sets each tab's card type from
expectedType - Shows slot labels and descriptions in the tab UI
- Validates required slots before rendering
Complete Example: KPI Area Chart
Here's the full implementation:
Sample Data File
MultiInputVisualProps Reference
Full TypeScript interface for multi-input visual props:
Settings vs. Slot Settings
Multi-input visuals support two levels of settings:
Global Settings
Defined in settings in the manifest. Stored on the config card. Apply to the entire visual.
Slot Settings
Defined in slotSettings in the manifest. Configurable per tab in the editor. Accessed via slotSettings[index].
When to use each:
| Setting Type | Use For | Examples |
|---|---|---|
Global (settings) | Visual-wide configuration | Grid lines, layout mode, animation |
Per-Slot (slotSettings) | Slot-specific overrides | Custom labels, colors per series |
Card Metadata
cardMetadata provides rich context about each slot's card configuration:
Access metadata by slot index:
Tab Metadata
tabMetadata provides lightweight tab context:
Useful for rendering tab labels or debugging:
Slot Configuration Modes
Different visuals need different slot structures. The manifest supports three modes:
Mode 1: Fixed Slots Only
For visuals with exact position requirements:
Result: Exactly 3 tabs, each with specific meaning. Users cannot add more.
Mode 2: Fully Dynamic (Repeating Pattern)
For visuals where all tabs follow the same pattern:
Result: 1 to 12 tabs, all treated as equal KPI inputs. Users can add/remove freely.
Mode 3: Fixed + Dynamic (Structured with Dynamic Tail)
For visuals with specific first slots and flexible additional slots:
Result: Tab 0 shows "Hero KPI", tabs 1+ show "Supporting". User can add up to 7 supporting KPIs.
Position Format Reference
The position field in slot definitions supports several formats:
| Position | Type | Meaning | Example |
|---|---|---|---|
0 | Fixed | Exactly position 0 (first tab) | Hero KPI |
1 | Fixed | Exactly position 1 (second tab) | Comparison metric |
"0+" | Dynamic | All positions, repeating | Grid of equal KPIs |
"1+" | Dynamic | Position 1 and all subsequent | Fixed hero + dynamic children |
"0-2" | Range | Positions 0, 1, and 2 only | Exactly 3 inputs |
Matching priority: exact > range > dynamic
Data Flow Diagram
How data flows from user configuration to your component:
Best Practices
Handle Incomplete Data
Multi-input visuals may render with partial data while users configure tabs. Always validate:
Use the Fallback Pattern for Titles
Always provide fallbacks for user-facing text:
Keep Slots Focused
Each slot should have a clear purpose. Don't overload a single slot with multiple data expectations.
Document Expected Data Shapes
In your manifest's docs.dataSchema, clearly describe what each slot expects:
Troubleshooting
Visual Shows "Configure tabs" Message
Cause: Required slots don't have data.
Fix: Ensure users have configured queries for all required slots. Check your empty state logic matches your slot requirements.
Data Array is Empty
Cause: Tab queries haven't executed or returned no rows.
Fix:
- Verify each tab has a data source configured
- Check query syntax in each tab
- Add console logging:
console.log('data:', data)
Slot Settings Not Applying
Cause: Accessing wrong index or settings not defined in manifest.
Fix:
- Verify
slotSettingsis defined in your manifest - Check you're accessing the correct array index
- Remember:
slotSettings[0]is slot 0, not slot 1
Tabs Not Auto-Creating
Cause: Missing visualType: 'multiple' or no slots array.
Fix: Ensure your manifest includes:
Related Topics
- Single-Input Visuals - Building standard custom visuals
- Number Formatting - Formatting numeric values
- Props Reference - Complete API documentation
- Card Tabs - How tabs work in Semaphor