
Building Omnistudio Flexcard
- 511 installs
- 787 repo stars
- Updated August 5, 2026
- forcedotcom/afv-library
This is a copy of building-omnistudio-flexcard by forcedotcom - installs and ranking accrue to the original listing.
building-omnistudio-flexcard is an agent skill that generates and validates production-ready Salesforce OmniStudio FlexCard definitions with automatic 130-point scoring for developers who build at-a-glance UI cards bound
About
building-omnistudio-flexcard is a Salesforce OmniStudio agent skill (version 1.0) for creating and reviewing FlexCard definitions. The skill configures data source bindings to Integration Procedures, designs card layouts, and scores existing OmniUiCard metadata against a 130-point rubric covering accessibility and performance. Developers reach for it when building new FlexCards, wiring data sources, or auditing card definitions before deployment. Use building-omnistudio-omniscript for OmniScripts and building-omnistudio-integration-procedure for Integration Procedures instead.
- Generates OmniUiCard definitions with declarative Integration Procedure data binding
- Validates against a 130-point scoring rubric across 7 categories
- Enforces SLDS styling, accessibility, conditional rendering and performance rules
- Handles card layouts, states, action buttons and deployment steps
- Hard-gated to FlexCards only — never triggers for OmniScripts or Integration Procedures
Building Omnistudio Flexcard by the numbers
- 511 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/forcedotcom/afv-library --skill building-omnistudio-flexcardAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 511 |
|---|---|
| repo stars | ★ 787 |
| Last updated | August 5, 2026 |
| Repository | forcedotcom/afv-library ↗ |
How do you build OmniStudio FlexCards with validation?
Generate and validate production-ready Salesforce OmniStudio FlexCard definitions with automatic 130-point scoring.
Who is it for?
Salesforce OmniStudio developers creating or reviewing FlexCards with Integration Procedure data sources.
Skip if: Developers building OmniScripts, Integration Procedures, or non-OmniStudio Salesforce LWC unrelated to FlexCards.
When should I use this skill?
A developer creates FlexCards, configures OmniStudio data sources, designs card layouts, or asks about OmniUiCard metadata review.
What you get
OmniUiCard FlexCard definitions, Integration Procedure data bindings, and a 130-point validation score report.
- FlexCard definition
- 130-point validation report
By the numbers
- Automatic 130-point FlexCard scoring rubric
- Skill version 1.0
Files
building-omnistudio-flexcard: OmniStudio FlexCard Creation and Validation
Expert OmniStudio engineer specializing in FlexCard UI components for Salesforce Industries. Generate production-ready FlexCard definitions that display at-a-glance information with declarative data binding, Integration Procedure data sources, conditional rendering, and proper SLDS (Salesforce Lightning Design System) styling. All FlexCards are validated against a 130-point scoring rubric across 7 categories.
Scope
- In scope: Creating and validating OmniStudio FlexCard definitions (
OmniUiCard); configuring Integration Procedure data sources; designing card layouts, states, and action buttons; scoring against the 130-point rubric; deployment and activation - Out of scope: Building OmniScripts (use
building-omnistudio-omniscript), creating Integration Procedures (usebuilding-omnistudio-integration-procedure), mapping full dependency trees (useanalyzing-omnistudio-dependencies), deploying metadata to org (usedeploying-metadata)
---
Core Responsibilities
1. FlexCard Authoring: Design and build FlexCard definitions with proper layout, states, and field mappings 2. Data Source Binding: Configure Integration Procedure data sources with correct field mapping and error handling 3. Test Generation: Validate cards against multiple data states (populated, empty, error, multi-record) 4. Documentation: Produce deployment-ready documentation with data source lineage and action mappings
Document Map
| Need | Document | Description |
|---|---|---|
| Best practices | references/best-practices.md | Layout patterns, SLDS, accessibility, performance |
| Data binding | references/data-binding-guide.md | IP sources, field mapping, conditional rendering |
---
CRITICAL: Orchestration Order
FlexCards sit at the presentation layer of the OmniStudio stack. Ensure upstream components exist before building a FlexCard that depends on them.
analyzing-omnistudio-dependencies → building-omnistudio-datamapper → building-omnistudio-integration-procedure → building-omnistudio-omniscript → building-omnistudio-flexcard (you are here)FlexCards consume data from Integration Procedures and can launch OmniScripts. Build the data layer first, then the presentation layer.
---
Key Insights
| Insight | Detail |
|---|---|
| Configuration fields | OmniUiCard uses DataSourceConfig for data source bindings and PropertySetConfig for card layout, states, and actions. There is NO Definition field on OmniUiCard in Core namespace. |
| Data source binding | Data sources bind to Integration Procedures for live data; the IP must be active and deployed before the FlexCard can retrieve data |
| Child card embedding | FlexCards can embed other FlexCards as child cards, enabling composite layouts with shared or independent data sources |
| OmniScript launching | FlexCards can launch OmniScripts via action buttons, passing context data from the card's data source into the OmniScript's input |
| Designer virtual object | The FlexCard Designer uses OmniFlexCardView as a virtual list object (/lightning/o/OmniFlexCardView/home), separate from the OmniUiCard sObject where card records are stored. Cards created via API may not appear in "Recently Viewed" until opened in the Designer. |
---
Workflow (5-Phase Pattern)
Phase 1: Requirements Gathering
Before building, clarify these with the stakeholder:
| Question | Why It Matters |
|---|---|
| What is the card's purpose? | Determines layout type and data density |
| Which data sources are needed? | Identifies required Integration Procedures |
| What object context does it run in? | Determines record-level vs. list-level display |
| What actions should the card expose? | Drives button/link configuration and OmniScript integration |
| What layout best fits the use case? | Single card, list, tabbed, or flyout |
| Are there conditional display rules? | Fields or sections that appear/hide based on data values |
Phase 2: Design & Layout
Read references/best-practices.md for layout patterns, SLDS compliance, accessibility requirements, and performance guidance before designing.
Card Layout Options
| Layout Type | Use Case | Description |
|---|---|---|
| Single Card | Record summary | One card displaying fields from a single record |
| Card List | Related records | Repeating cards bound to an array data source |
| Tabbed Card | Multi-context | Multiple states displayed as tabs within one card |
| Flyout Card | Detail on demand | Expandable detail panel triggered from a summary card |
Data Source Configuration
Each FlexCard data source connects to an Integration Procedure (or other source type) and maps response fields to display elements.
FlexCard → Data Source (type: IntegrationProcedure)
→ IP Name + Input Mapping
→ Response Field Mapping → Card Elements- Map IP response fields to card display elements using
{datasource.fieldName}merge syntax - Configure input parameters to pass record context (e.g.,
{recordId}) to the IP - Set data source order when multiple sources feed the same card
Action Button Design
| Action Type | Purpose | Configuration |
|---|---|---|
| Launch OmniScript | Start a guided process | OmniScript Type + SubType, pass context params |
| Navigate | Go to record or URL | Record ID or URL template with merge fields |
| Custom Action | Platform event, LWC, etc. | Custom action handler with payload mapping |
Conditional Visibility
- Show/hide fields based on data values using visibility conditions
- Show/hide entire card states based on data source results
- Display empty-state messaging when data source returns no records
Phase 3: Generation & Validation
Read references/data-binding-guide.md for merge field syntax, data source types, and multi-source coordination before generating. Read references/scoring-rubric.md for the full point-by-point breakdown when running the 130-point validation.
1. Generate the FlexCard definition JSON 2. Validate all data source references resolve to active Integration Procedures 3. Run the 130-point scoring rubric (see Scoring section below) 4. Verify merge field syntax matches IP response structure 5. Check accessibility attributes on all interactive elements
Phase 4: Deployment
1. Ensure all upstream Integration Procedures are deployed and active 2. Run a dry-run check: use the deploying-metadata skill with --dry-run before committing 3. Deploy the FlexCard metadata (OmniUiCard) — sf project deploy start is safe to re-run; it upserts existing records 4. Activate the FlexCard in the target org 5. Embed the FlexCard in the target Lightning page, OmniScript, or parent FlexCard 6. If deploy fails: check error output for specific cause — common issues: upstream IP not deployed (Cannot find OmniIntegrationProcedure), missing namespace prefix (Entity not found), or FlexCard still in Draft status (activate before retrieving)
Phase 5: Testing
Test each FlexCard against multiple data scenarios:
| Scenario | What to Verify |
|---|---|
| Populated data | All fields render correctly, merge fields resolve |
| Empty data | Empty-state message displays, no broken merge fields |
| Error state | Graceful handling when IP returns an error or times out |
| Multi-record | Card list renders correct number of items, pagination works |
| Action buttons | OmniScript launches with correct pre-populated data |
| Conditional fields | Visibility rules toggle correctly based on data values |
| Mobile | Card layout adapts to smaller viewport widths |
---
Generation Guardrails
Avoid these patterns when generating FlexCard definitions:
| Anti-Pattern | Why It's Wrong | Correct Approach |
|---|---|---|
| Referencing non-existent IP data sources | Card fails to load data at runtime | Verify IP exists and is active before binding |
| Hardcoded colors in styles | Breaks SLDS theming and dark mode | Use SLDS design tokens and CSS custom properties |
| Missing accessibility attributes | Fails WCAG compliance | Add aria-label, role, and keyboard handlers |
| Excessive nested child cards | Performance degrades with deep nesting | Limit to 2 levels of nesting; flatten where possible |
| Ignoring empty states | Broken UI when data source returns no records | Configure explicit empty-state messaging |
| Hardcoded record IDs | Card breaks across environments | Use merge fields and context-driven parameters |
---
Scoring Rubric (130 Points)
All FlexCards are validated against 7 categories. Thresholds: ✅ 90+ (Deploy) | ⚠️ 67-89 (Review) | ❌ <67 (Block - fix required)
| Category | Points | Criteria |
|---|---|---|
| Design & Layout | 25 | Appropriate layout type, logical field grouping, responsive design, consistent spacing, clear visual hierarchy |
| Data Binding | 20 | Correct IP references, proper merge field syntax, input parameter mapping, multi-source coordination |
| Actions & Navigation | 20 | Action buttons configured correctly, OmniScript launch params mapped, navigation targets valid, action labels descriptive |
| Styling | 20 | SLDS tokens used (no hardcoded colors), consistent typography, proper use of card/tile patterns, dark mode compatible |
| Accessibility | 15 | aria-label on interactive elements, keyboard navigable actions, sufficient color contrast, screen reader friendly field labels |
| Testing | 15 | Verified with populated data, empty state, error state, multi-record scenario, and mobile viewport |
| Performance | 15 | Data source calls minimized, child card nesting limited (max 2 levels), no redundant IP calls, lazy loading for non-visible states |
Read references/scoring-rubric.md for the full per-criterion breakdown of all 7 categories.
---
CLI Commands
Read scripts/flexcard-commands.sh for all FlexCard CLI commands (query, retrieve, deploy). Replace <org> with your org alias and <Name> with the FlexCard API name.
---
Data Source Binding
FlexCard Data Source Configuration
The DataSourceConfig field on OmniUiCard contains the data source bindings as JSON. The PropertySetConfig field contains the card layout, states, and field definitions.
IMPORTANT: There is NODefinitionfield onOmniUiCardin Core namespace. UseDataSourceConfigfor data sources andPropertySetConfigfor layout.
Read assets/omni-ui-card.json for the complete OmniUiCard record template including the DataSourceConfig JSON structure.
Data Source Types
| Type | dataSource.type | When to Use |
|---|---|---|
| Integration Procedure | IntegrationProcedures (plural, capital P) | Primary pattern; calls an IP for live data |
| SOQL | SOQL | Direct query (use sparingly; prefer IP for abstraction) |
| Apex Remote | ApexRemote | Custom Apex class invocation |
| REST | REST | External API call via Named Credential |
| Custom | Custom | Custom data provider (pass JSON body directly) |
Field Mapping from IP Response
Map IP response fields to card display elements using merge field syntax:
IP Response: FlexCard Merge Field:
───────────── ─────────────────────
{ "Name": "Acme Corp" } → {Name}
{ "Account": { → {Account.Name}
"Name": "Acme Corp"
}
}
{ "records": [ → {records[0].Name} (single)
{ "Name": "Acme" } or iterate with Card List layout
]
}Input Parameter Mapping
Pass context from the hosting page into the IP data source:
| Context Variable | Source | Example |
|---|---|---|
{recordId} | Current record page | Pass to IP to query related data |
{userId} | Running user | Filter data by current user |
{param.customKey} | URL parameter or parent card | Pass from parent FlexCard or URL |
---
Cross-Skill Integration
| Skill | Relationship to building-omnistudio-flexcard |
|---|---|
| building-omnistudio-integration-procedure | Build the IP data sources that FlexCards consume |
| building-omnistudio-omniscript | Build the OmniScripts that FlexCard action buttons launch |
| building-omnistudio-datamapper | Build DataRaptors/DataMappers that IPs use under the hood |
| analyzing-omnistudio-dependencies | Analyze dependency chains across FlexCards, IPs, and OmniScripts |
| deploying-metadata | Deploy FlexCard metadata along with upstream dependencies |
| generating-lwc-components | Build custom LWC components embedded within FlexCards |
---
Gotchas
| Scenario | Handling |
|---|---|
| Empty data | Configure an explicit empty-state with a user-friendly message; do not show raw "No data" or blank card |
| Error states | Display a meaningful error message when the IP data source fails; log the error for debugging |
| Mobile responsiveness | Use single-column layout for mobile; avoid horizontal scrolling; test at 320px viewport width |
| Long text values | Truncate with ellipsis and provide a flyout or tooltip for full text |
| Large record sets | Use card list with pagination; limit initial load to 10-25 records |
| Null field values | Use conditional visibility to hide fields with null values rather than showing empty labels |
| Mixed data freshness | When multiple data sources have different refresh rates, display a "last updated" indicator |
---
FlexCard vs LWC Decision Guide
| Factor | FlexCard | LWC |
|---|---|---|
| Build method | Declarative (drag-and-drop) | Code (JS, HTML, CSS) |
| Data binding | Integration Procedure merge fields | Wire service, Apex, GraphQL |
| Best for | At-a-glance information display | Complex interactive UIs |
| Testing | Manual + data state verification | Jest unit tests + manual |
| Customization | Limited to OmniStudio framework | Full platform flexibility |
| Reuse | Embed as child cards | Import as child components |
| When to choose | Standard card layouts with IP data | Custom behavior, animations, complex state |
---
Dependencies
Required: Target org with OmniStudio (Industries Cloud) license, sf CLI authenticated For Data Sources: Active Integration Procedures deployed to the target org For Actions: Active OmniScripts deployed (if action buttons launch OmniScripts) Scoring: Block deployment if score < 67
Idempotency: sf project deploy start upserts metadata — safe to re-run without creating duplicates. Query first to confirm current state: see scripts/flexcard-commands.sh.
Namespace handling: In managed-package orgs, the metadata type may be prefixed (e.g., omnistudio__OmniUiCard). Check sfdx-project.json for the namespace. See scripts/flexcard-commands.sh for the namespaced deploy command.
Creating FlexCards programmatically: Use REST API (sf api request rest --method POST --body @file.json). Required fields: Name, VersionNumber, OmniUiCardType (e.g., Child). Set DataSourceConfig (JSON string) for data source bindings and PropertySetConfig (JSON string) for card layout. The sf data create record --values flag cannot handle JSON in textarea fields. Activate by updating IsActive=true after creation.
---
Output Expectations
Deliverables produced by this skill:
- FlexCard JSON definition (
assets/omni-ui-card.jsontemplate) —OmniUiCardrecord ready for REST API creation or metadata deployment - Data source binding block —
DataSourceConfigJSON mapping Integration Procedure inputs and response fields to card elements - Card layout config —
PropertySetConfigJSON defining card states, field display, conditional visibility, and action buttons - Validation report — 130-point score across 7 categories with deploy/review/block threshold result
- Deployment checklist — confirms upstream IPs are active, FlexCard is activated, and embedded in target Lightning page or parent FlexCard
---
External References
- OmniStudio FlexCards (Trailhead) — Official learning module for FlexCard fundamentals and guided setup
- OmniStudio Developer Guide — Technical reference for FlexCard metadata, data source configuration, and component properties
- Salesforce Industries Documentation — FlexCard configuration guide covering layout, states, and actions
---
Reference File Index
| File | When to read |
|---|---|
assets/omni-ui-card.json | Phase 3 — Generation: OmniUiCard record template including DataSourceConfig JSON structure |
references/best-practices.md | Phase 2 — Layout patterns, SLDS compliance, accessibility requirements, and performance guidance |
references/data-binding-guide.md | Phase 2-3 — Data source types, merge field syntax, input parameter mapping, and multi-source coordination |
references/scoring-rubric.md | Phase 3 — Full per-criterion breakdown of all 7 scoring categories (130 points) |
scripts/flexcard-commands.sh | Phase 4 — All CLI commands for querying, retrieving, and deploying FlexCard metadata |
{
"Name": "{{CardName}}",
"VersionNumber": 1,
"OmniUiCardType": "Child",
"IsActive": false,
"Description": "{{Description}}",
"DataSourceConfig": "{\"dataSource\":{\"type\":\"IntegrationProcedures\",\"value\":{\"ipMethod\":\"{{IPType}}_{{IPSubType}}\",\"vlocityAsync\":false,\"inputMap\":{\"recordId\":\"{recordId}\"},\"resultVar\":\"\"},\"orderBy\":{\"name\":\"\",\"isReverse\":\"\"},\"contextVariables\":[]}}",
"PropertySetConfig": "{\"states\":[{\"conditions\":{\"group\":[],\"id\":\"state-condition-object\",\"operator\":\"\"},\"fields\":[],\"id\":\"state-id-0\",\"isSmartAction\":false,\"name\":\"Active\",\"smartAction\":{},\"styleObject\":{\"class\":\"slds-card\",\"container\":{\"class\":\"slds-card\"}}}],\"title\":\"{{CardTitle}}\",\"iconName\":\"\",\"theme\":\"\",\"isFlyout\":false,\"datasource\":{\"contextVariables\":[],\"orderBy\":{},\"type\":\"\"}}",
"AuthorName": "{{AuthorName}}"
}
Credits
Official Salesforce OmniStudio tooling for FlexCard metadata authoring and validation. Primary inspiration for the skill's data source binding patterns and definition structure.
---
<!-- Parent: building-omnistudio-flexcard/SKILL.md -->
FlexCard Best Practices
Layout Design Patterns
Single Card
Use for displaying summary information about a single record. Group related fields into logical sections.
┌──────────────────────────────────┐
│ Header: Record Name │
├──────────────────────────────────┤
│ Section 1: Key Details │
│ ┌────────────┬─────────────┐ │
│ │ Field A │ Field B │ │
│ │ Field C │ Field D │ │
│ └────────────┴─────────────┘ │
├──────────────────────────────────┤
│ Section 2: Status │
│ ┌──────────────────────────┐ │
│ │ Status Badge │ Date │ │
│ └──────────────────────────┘ │
├──────────────────────────────────┤
│ [Action Button 1] [Action 2] │
└──────────────────────────────────┘Guidelines:
- Limit to 8-10 fields per card to avoid information overload
- Place the most important fields in the top section
- Use consistent field alignment (label-left or label-top)
- Group related fields in the same row when they share context
Card List
Use for displaying a collection of related records. Each card in the list renders from one item in the data source array.
┌──────────────────────────────────┐
│ Card 1: Record A │
│ Field 1 | Field 2 | [Action] │
├──────────────────────────────────┤
│ Card 2: Record B │
│ Field 1 | Field 2 | [Action] │
├──────────────────────────────────┤
│ Card 3: Record C │
│ Field 1 | Field 2 | [Action] │
└──────────────────────────────────┘
Showing 1-3 of 15 [Next →]Guidelines:
- Keep each list card compact (3-5 fields maximum)
- Include a clear identifier field (Name, Title, or ID) in each card
- Add pagination when the data source can return more than 10 records
- Use consistent card height to maintain visual rhythm
- Provide a "View All" link when the list is truncated
Tabbed Card
Use when a single record has multiple contexts worth displaying. Each tab represents a different state with its own data source or field set.
┌──────────────────────────────────┐
│ [Tab 1: Overview] [Tab 2: History] [Tab 3: Related] │
├──────────────────────────────────┤
│ Tab 1 Content │
│ ┌──────────────────────────┐ │
│ │ Fields for this context │ │
│ └──────────────────────────┘ │
└──────────────────────────────────┘Guidelines:
- Limit to 3-5 tabs to avoid horizontal overflow
- Use concise tab labels (1-2 words)
- Load non-active tab data lazily (on tab selection)
- Mark the default active tab based on the most common use case
Flyout Card
Use for progressive disclosure: show a summary, then expand for details on demand.
┌──────────────────────────────────┐
│ Summary: Key Fields [▼ More] │
└──────────────────────────────────┘
↓ (on click)
┌──────────────────────────────────┐
│ Summary: Key Fields [▲ Less] │
├──────────────────────────────────┤
│ Detail Section │
│ Additional fields, history, │
│ related records, etc. │
└──────────────────────────────────┘Guidelines:
- Keep the summary to 2-3 fields that answer "what is this?"
- Load flyout content on demand, not on initial card render
- Provide a clear visual indicator for the expand/collapse action
- Maintain the flyout state if the user scrolls away and returns
---
Data Source Optimization
Minimize IP Calls
- Use a single IP that returns all required data rather than multiple IPs for individual fields
- If the card has multiple data sources, ensure they do not query overlapping data
- Cache IP responses where the data does not change frequently (use IP caching options)
Input Parameter Efficiency
- Pass only the parameters the IP needs; do not forward the entire page context
- Use
{recordId}as the primary context parameter for record-level cards - Avoid passing large objects as input parameters; pass IDs and let the IP query
Response Structure
- Design IP responses to match the FlexCard's field mapping structure directly
- Avoid deep nesting in IP responses when the FlexCard only needs top-level fields
- Use
resultListPathto point directly to the array node in list-type cards
Error Handling in Data Sources
- Configure a fallback state for when the IP returns an error
- Set reasonable timeout values for data source calls
- Log data source errors for debugging without exposing raw error messages to end users
---
Action Configuration
OmniScript Launch Actions
| Consideration | Guidance |
|---|---|
| Parameter mapping | Map card data fields to OmniScript input fields explicitly |
| Pre-population | Pass enough context for the OmniScript to pre-fill known values |
| Return handling | Refresh the FlexCard data source after the OmniScript completes |
| Error states | Handle the case where the OmniScript fails or is cancelled |
Navigation Actions
| Consideration | Guidance |
|---|---|
| Record navigation | Use {recordId} merge fields, not hardcoded IDs |
| URL navigation | Use relative URLs for internal Salesforce navigation |
| External URLs | Open in a new tab; warn users if leaving Salesforce |
| Conditional navigation | Disable navigation buttons when the target is invalid |
Action Button Placement
- Place primary actions at the bottom of the card or in the card header
- Limit to 2-3 actions per card; use a "More Actions" overflow menu for additional actions
- Use descriptive button labels ("Submit Claim", not "Submit" or "Go")
- Visually distinguish primary actions (filled button) from secondary actions (outline button)
---
SLDS Compliance for Styling
Required Practices
- Use SLDS design tokens for all colors, spacing, font sizes, and border radii
- Use
slds-cardorslds-tilepatterns for card containers - Use
slds-gridandslds-colfor multi-column layouts within cards - Apply
slds-text-heading_smalland related text utilities for consistent typography
Color Usage
Correct: Use SLDS token → var(--slds-g-color-brand-base-50)
Wrong: Hardcoded hex → #0176d3
Wrong: Hardcoded rgb → rgb(1, 118, 211)- Status indicators: use
slds-badgewith appropriate color variants - Background colors: use
slds-boxwithslds-theme_shadeorslds-theme_default - Text colors: rely on inherited SLDS text colors; override only when necessary
Spacing
- Use SLDS spacing utilities:
slds-m-top_small,slds-p-around_medium, etc. - Maintain consistent spacing between card sections (use
slds-m-bottom_medium) - Do not use pixel values directly; map to the SLDS spacing scale
Dark Mode Compatibility
- All colors must come from SLDS CSS custom properties (
--slds-g-color-*) - Test card rendering in both light and dark modes
- Avoid background images that only work on light backgrounds
- Use
currentColorfor icon fills so they adapt to the text color
---
Accessibility Requirements
Interactive Elements
- Every button must have an
aria-labelor visible text label - Links must have descriptive text (not "Click here" or "Learn more" without context)
- Icon-only buttons require
aria-labeldescribing the action
Keyboard Navigation
- All action buttons must be focusable via Tab key
- Buttons must activate on Enter and Space key presses
- Tab order must follow the visual reading order (top-to-bottom, left-to-right)
- Flyout expand/collapse must be keyboard accessible
Screen Reader Support
- Use semantic heading elements for card titles and section headers
- Data fields should have associated labels readable by screen readers
- Status indicators must convey meaning through text, not color alone
- Dynamic content updates should use
aria-liveregions
Color Contrast
- Text on card backgrounds must meet WCAG 2.1 AA contrast ratio (4.5:1)
- Interactive element boundaries must have 3:1 contrast against their background
- Do not use color as the sole method of conveying information (add icons or text)
---
Performance with Large Data Sets
Data Volume Guidelines
| Record Count | Recommended Approach |
|---|---|
| 1-5 | Load all records in a single card list |
| 6-25 | Load with pagination (show 5-10 per page) |
| 26-100 | Server-side pagination via IP; load one page at a time |
| 100+ | Reconsider the UX; use search/filter instead of browsing |
Rendering Performance
- Limit child card nesting to 2 levels maximum
- Avoid rendering more than 25 cards simultaneously in a card list
- Use conditional visibility to hide sections rather than rendering and hiding with CSS
- Lazy-load tab content and flyout details on user interaction
Data Source Performance
- Set appropriate IP cache durations for data that does not change frequently
- Avoid chaining multiple IPs when a single IP can return all needed data
- Use
resultListPathto avoid client-side data transformation - Monitor IP execution times; optimize IPs that take longer than 2 seconds
---
Child Card Composition
When to Use Child Cards
- The parent card displays summary data and the child card shows related detail
- Multiple cards share a common layout pattern that should be defined once
- Different sections of a card require independent data sources
Composition Guidelines
- Pass data from parent to child via input parameters, not global variables
- Keep child cards self-contained: they should work independently for testing
- Limit nesting to 2 levels (parent → child → grandchild maximum)
- Document the parent-child data flow in the FlexCard's description
Data Flow Pattern
Parent FlexCard
├── Data Source: IP_GetAccountSummary
│ └── Passes {AccountId} to child
└── Child FlexCard: AccountContacts
└── Data Source: IP_GetContacts
└── Input: {AccountId} from parentAvoiding Composition Anti-Patterns
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Deep nesting (3+ levels) | Performance degradation, hard to debug | Flatten the structure; combine data in the IP |
| Shared mutable state | Child cards modifying parent data | Use one-way data flow (parent → child only) |
| Duplicate data sources | Same IP called by parent and child | Consolidate into parent data source; pass results down |
| Tightly coupled children | Child card cannot function without parent | Design children to accept input parameters and work standalone |
<!-- Parent: building-omnistudio-flexcard/SKILL.md -->
FlexCard Data Binding Guide
Integration Procedure Data Source Configuration
Basic IP Binding
The most common FlexCard data source is an Integration Procedure. The data source configuration specifies which IP to call, what input to send, and where to find the results in the IP response.
{
"dataSource": {
"type": "IntegrationProcedures",
"value": {
"ipMethod": "Type_SubType",
"inputMap": {
"recordId": "{recordId}"
},
"resultListPath": ""
}
}
}| Property | Purpose | Example |
|---|---|---|
type | Data source type identifier | "IntegrationProcedures" (plural, capital P) |
ipMethod | IP Type and SubType joined by underscore | "Account_GetSummary" |
inputMap | Key-value pairs sent as IP input | { "recordId": "{recordId}" } |
resultListPath | JSON path to the array node for list-type cards | "records" or "" for root |
IP Method Naming Convention
The ipMethod value combines the IP's Type and SubType fields:
IP Type: "Account"
IP SubType: "GetSummary"
ipMethod: "Account_GetSummary"Ensure the IP is active and the Type/SubType match exactly (case-sensitive).
Input Map Parameters
Input parameters pass context from the FlexCard's hosting environment into the IP:
{
"inputMap": {
"recordId": "{recordId}",
"accountId": "{Account.Id}",
"status": "Active",
"limit": 10
}
}| Syntax | Resolves To |
|---|---|
{recordId} | The current record's ID from the hosting Lightning page |
{Account.Id} | A field from a parent FlexCard's data source |
"Active" | A static/literal value |
{param.customKey} | A URL parameter or custom context variable |
---
Field Mapping Syntax
Basic Field Mapping
Map IP response fields to FlexCard display elements using curly-brace merge syntax:
IP Response JSON: FlexCard Merge Field:
───────────────── ─────────────────────
{ "Name": "Acme Corp" } → {Name}
{ "Status": "Active" } → {Status}
{ "Amount": 50000 } → {Amount}Nested Field Mapping
Access nested objects in the IP response using dot notation:
IP Response JSON: FlexCard Merge Field:
───────────────── ─────────────────────
{ → {Account.Name}
"Account": { → {Account.Industry}
"Name": "Acme Corp", → {Account.Owner.Name}
"Industry": "Technology",
"Owner": {
"Name": "Jane Smith"
}
}
}Array Field Mapping
For card list layouts, set resultListPath to the array node. Each card in the list renders one item from the array:
{
"dataSource": {
"value": {
"ipMethod": "Contact_GetRelated",
"resultListPath": "contacts"
}
}
}IP Response: Each Card Renders:
──────────── ──────────────────
{ Card 1: {Name} → "Alice"
"contacts": [ {Email} → "alice@acme.com"
{ "Name": "Alice", "Email": "..." },
{ "Name": "Bob", "Email": "..." }, Card 2: {Name} → "Bob"
{ "Name": "Carol", "Email": "..." } {Email} → "bob@acme.com"
]
} Card 3: {Name} → "Carol"
{Email} → "carol@acme.com"Formatted Field Display
Apply formatting to merge fields for display:
| Format Need | Approach |
|---|---|
| Currency | Format in the IP response (e.g., return "$50,000.00") or use OmniStudio formatting |
| Date | Return ISO date from IP; apply date formatting in the FlexCard field configuration |
| Boolean | Use conditional rendering to show icons or text instead of true/false |
| Percentage | Return as a number; format display in the FlexCard field |
---
Conditional Rendering Based on Data
Field-Level Visibility
Show or hide individual fields based on a data value:
Condition: {Status} == "Active"
Action: Show the "Renewal Date" field
Condition: {Amount} > 100000
Action: Show the "High Value" badge
Condition: {Email} != null
Action: Show the email field (hide when null)State-Level Visibility
FlexCards support multiple states. Each state can have visibility conditions:
| State | Visibility Condition | Use Case |
|---|---|---|
| Default | Always visible | Primary card content |
| Empty | Data source returns 0 records | "No records found" message |
| Error | Data source returns error | Error notification |
| Conditional | Field matches specific value | Status-specific card layout |
Conditional Rendering Operators
| Operator | Syntax | Example |
|---|---|---|
| Equals | == | {Status} == "Active" |
| Not equals | != | {Status} != "Closed" |
| Greater than | > | {Amount} > 10000 |
| Less than | < | {DaysOpen} < 30 |
| Contains | CONTAINS | {Name} CONTAINS "Corp" |
| Is null | == null | {Email} == null |
| Is not null | != null | {Phone} != null |
Conditional Styling
Apply different styles based on data values:
If {Status} == "Active" → Green badge (slds-badge slds-theme_success)
If {Status} == "Expired" → Red badge (slds-badge slds-theme_error)
If {Status} == "Pending" → Yellow badge (slds-badge slds-theme_warning)Use SLDS theme classes rather than inline color styles to maintain dark mode compatibility.
---
Multi-Data-Source Cards
When to Use Multiple Data Sources
- The card displays data from unrelated objects that cannot be fetched in a single IP
- Different sections of the card have different refresh requirements
- A child card needs its own independent data source
Configuration Pattern
FlexCard: AccountOverview
├── Data Source 1: "Account_GetSummary"
│ Input: { "recordId": "{recordId}" }
│ Fields: {ds1.Name}, {ds1.Industry}, {ds1.Status}
│
├── Data Source 2: "Case_GetOpenCount"
│ Input: { "accountId": "{recordId}" }
│ Fields: {ds2.openCaseCount}, {ds2.lastCaseDate}
│
└── Data Source 3: "Opportunity_GetPipeline"
Input: { "accountId": "{recordId}" }
Fields: {ds3.totalPipeline}, {ds3.nextCloseDate}Data Source Naming
When a card has multiple data sources, reference fields using the data source name prefix:
Single data source: {Name}
Multiple data sources: {ds1.Name} or {accountSummary.Name}Load Order and Dependencies
- Data sources load in parallel by default
- If Data Source 2 depends on a value from Data Source 1, configure the dependency order
- Use conditional rendering to hide sections until their data source has loaded
- Display a loading indicator while data sources are in progress
Coordinating Multiple Sources
| Pattern | Description | Use Case |
|---|---|---|
| Parallel load | All sources fetch simultaneously | Independent data sets |
| Sequential load | Source B waits for Source A | Source B needs a value from Source A's response |
| Conditional load | Source B only loads if Source A meets a condition | Avoid unnecessary API calls |
---
Error Handling for Failed Data Sources
Common Failure Modes
| Failure | Cause | User Impact |
|---|---|---|
| IP not found | IP name misspelled or IP not deployed | Card shows no data; console error |
| IP inactive | IP exists but is not activated | Card shows no data |
| IP timeout | IP takes too long to execute | Card shows loading indefinitely |
| IP error response | IP logic throws an exception | Card may show partial data or error state |
| Auth failure | User lacks permission to run the IP | Card shows no data; access error |
| Network error | Connectivity issue between client and server | Card shows no data |
Error State Design
Configure an explicit error state rather than letting the card fail silently:
┌──────────────────────────────────┐
│ ⚠ Unable to load account data │
│ │
│ The data source returned an │
│ error. Try refreshing the page. │
│ │
│ [Refresh] [Contact Support] │
└──────────────────────────────────┘Error State Guidelines:
- Use plain language, not technical error codes
- Provide an actionable next step (refresh, retry, contact admin)
- Log the technical error details for debugging (not displayed to end users)
- Do not show a blank card with no explanation
Fallback Strategies
| Strategy | Implementation | When to Use |
|---|---|---|
| Cached data | Show previously loaded data with a "stale" indicator | Data changes infrequently |
| Partial render | Show fields that loaded; hide failed sections | Multi-source card where only one source fails |
| Empty state | Show "No data available" with context | Single-source card where the source fails |
| Retry | Provide a manual retry button | Transient errors (network, timeout) |
Debugging Data Source Issues
1. Check IP activation: Query SELECT Name, IsActive FROM OmniProcess WHERE Name = 'Type_SubType' 2. Verify IP input: Use the OmniStudio Preview tool to test the IP with the same input parameters 3. Check field paths: Ensure merge field paths ({field.subfield}) match the actual IP response structure 4. Review permissions: Confirm the running user has access to the IP and the underlying objects 5. Inspect browser console: FlexCard data source errors appear in the browser developer console 6. Test with static data: Temporarily configure the FlexCard with a static JSON data source to isolate whether the issue is the IP or the card
Data Source Validation Checklist
Before deploying a FlexCard, verify each data source:
- [ ] IP exists in the target org
- [ ] IP is activated
- [ ] IP Type and SubType match the
ipMethodvalue exactly (case-sensitive) - [ ] Input parameters use correct merge field syntax
- [ ]
resultListPathpoints to the correct array node (for list cards) - [ ] All merge fields in the card map to actual fields in the IP response
- [ ] Error state is configured for graceful failure
- [ ] Empty state is configured for zero-record responses
- [ ] Data source has been tested with real data in a sandbox
FlexCard Scoring Rubric: Breakdown Detail
Detailed point-by-point scoring criteria for the 130-point FlexCard validation. Read during Phase 3 when running the full scoring rubric.
Design & Layout (25 points)
| Criterion | Points | Description |
|---|---|---|
| Layout type matches use case | 5 | Single, list, tabbed, or flyout chosen appropriately |
| Field grouping is logical | 5 | Related fields are visually grouped together |
| Responsive behavior | 5 | Card adapts to different viewport widths |
| Consistent spacing | 5 | Margins and padding follow SLDS (Salesforce Lightning Design System) spacing scale |
| Visual hierarchy | 5 | Primary information is prominent, secondary is de-emphasized |
Data Binding (20 points)
| Criterion | Points | Description |
|---|---|---|
| IP references are valid | 5 | All referenced IPs exist and are active |
| Merge field syntax correct | 5 | {datasource.field} paths resolve to actual IP response fields |
| Input parameters mapped | 5 | Record context passed correctly to IP inputs |
| Multi-source coordination | 5 | Multiple data sources load in correct order without conflicts |
Actions & Navigation (20 points)
| Criterion | Points | Description |
|---|---|---|
| Action buttons functional | 5 | All buttons trigger their configured actions |
| OmniScript params mapped | 5 | Context data flows correctly into launched OmniScripts |
| Navigation targets valid | 5 | Record and URL navigation resolves correctly |
| Labels are descriptive | 5 | Action labels clearly communicate what the action does |
Styling (20 points)
| Criterion | Points | Description |
|---|---|---|
| SLDS tokens used | 5 | Colors, fonts, spacing via design tokens |
| Consistent typography | 5 | Text sizes follow SLDS type scale |
| Card pattern compliance | 5 | Uses standard SLDS card or tile patterns |
| Dark mode compatible | 5 | No hardcoded colors; works with SLDS dark theme |
Accessibility (15 points)
| Criterion | Points | Description |
|---|---|---|
| ARIA labels on interactive elements | 5 | Buttons, links, and inputs have accessible names |
| Keyboard navigable | 5 | All actions reachable via Tab, activated via Enter/Space |
| Color contrast sufficient | 5 | Meets WCAG 2.1 AA contrast ratio (4.5:1 for text) |
Testing (15 points)
| Criterion | Points | Description |
|---|---|---|
| Populated data verified | 3 | Card renders correctly with full data |
| Empty state verified | 3 | Empty-state message displays properly |
| Error state verified | 3 | Graceful handling of IP errors |
| Multi-record verified | 3 | Card list renders correct items |
| Mobile viewport verified | 3 | Layout adapts to small screens |
Performance (15 points)
| Criterion | Points | Description |
|---|---|---|
| Data source calls minimized | 5 | No redundant or duplicate IP invocations |
| Child card nesting limited | 5 | Maximum 2 levels of nested child cards |
| Lazy loading for hidden states | 5 | Non-visible tabs/flyouts load on demand |
#!/usr/bin/env bash
# FlexCard CLI Commands
# Replace <org> with your org alias and <Name> with the FlexCard API name.
# Query active FlexCards in the org
sf data query -q "SELECT Id,Name,DataSourceConfig,PropertySetConfig,IsActive FROM OmniUiCard WHERE IsActive=true LIMIT 200" -o <org>
# Retrieve a specific FlexCard by name
sf project retrieve start -m OmniUiCard:<Name> -o <org>
# Deploy a FlexCard to the target org
sf project deploy start -m OmniUiCard:<Name> -o <org>
# Retrieve all FlexCards
sf project retrieve start -m OmniUiCard -o <org>
# Deploy all OmniStudio metadata (FlexCards + dependencies)
sf project deploy start -m OmniUiCard -m OmniIntegrationProcedure -m OmniScript -o <org>
# Check deploy status (use job ID from deploy output)
sf project deploy report --job-id <jobId> -o <org>
# In namespaced orgs (managed package), prefix the metadata type:
# sf project deploy start -m omnistudio__OmniUiCard:<Name> -o <org>
Related skills
How it compares
Pick this over generic Salesforce LWC skills when the artifact is an OmniStudio FlexCard with Integration Procedure data bindings.
FAQ
What scoring does building-omnistudio-flexcard apply?
building-omnistudio-flexcard applies automatic 130-point scoring when validating FlexCard definitions, evaluating layout, data source configuration, accessibility, and performance on OmniUiCard metadata.
When should I not use building-omnistudio-flexcard?
Do not use building-omnistudio-flexcard for OmniScripts or Integration Procedures. Use building-omnistudio-omniscript or building-omnistudio-integration-procedure for those OmniStudio artifact types.