This project demonstrates how to create a custom application that embeds Domo cards and utilizes postMessage communication between your custom frames and Domo's embedded analytics.
This instructional example teaches developers how to:
- Embed Domo cards in custom applications
- Implement bidirectional communication using postMessage API
- Handle different types of messages and events
- Create a robust communication framework for embedded analytics
- Configurable card embedding with custom dimensions
- Automatic iframe setup with security considerations
- Real-time card configuration updates
- Send messages to embedded cards (filters, refresh commands, custom events)
- Receive messages from embedded cards (user interactions, data updates)
- Real-time message logging and debugging
- Apply filters to embedded cards
- Trigger data refreshes
- Export data functionality
- Send custom events and commands
- Real-time logging of all postMessage communications
- Message type categorization (sent/received/system)
- Timestamped message history
- JSON data formatting and display
This project includes several // TODO:
comments to guide further development. Below are the instructions for addressing them:
-
Page Filters Manager (
src/components/page-filters-manager/index.tsx
):- Line 24 & 46: Update the example filter logic to match the filters you want to apply in your application. Replace the placeholder filter (
Talent_Class
) with the actual column, data type, and values relevant to your use case.const newFilter: PageFilter = { column: 'Your_Column_Name', columnType: ColumnType.STRING, // Adjust based on your data type dataType: PageFilterDataType.String, // Adjust based on your data type label: 'Your Label', operand: PageFilterOperator.In, // Adjust based on your filter operation values: ['Value1', 'Value2'], // Replace with actual filter values };
- Line 24 & 46: Update the example filter logic to match the filters you want to apply in your application. Replace the placeholder filter (
-
App Component (
src/components/app/index.tsx
):- Line 53: Update the
iframeUrl
property of theEmbeddedCard
component to use the correct Domo instance and card embed IDs for your application.<EmbeddedCard iframeUrl="https://your-instance.domo.com/embed/card/private/your-embed-id" title="Your Card Title" width={1000} height={400} />
- Line 53: Update the
- Node.js (v18 or higher)
- Yarn package manager
- Domo Developer Account
- Access to Domo instance with embedding enabled
- Ryuu (DomoApps CLI) installed
-
Clone and install dependencies:
git clone <repository-url> cd embed-frames-example yarn install
-
Import The Sample Data:
- CSV is located in the docs folder
- Upload as a new dataset in your instance
- Make a note of the dataset ID for later use
-
Login to your instance with Ryuu:
domo login
-
Update configuration:
- Edit
src/components/embedded-card/index.tsx
- Replace
your-domo-instance
with your actual Domo instance name - Update the
domoInstance
prop in the EmbeddedCard component
- Edit
-
Run the development server:
yarn start
-
Upload to Domo (optional):
yarn upload
- Enter a Card ID: Input a valid Domo card ID in the configuration section
- Configure the card: Set title and display options
- View the embedded card: The card will load in an iframe
- Test communication: Use the control buttons to send messages
// Filter application
iframe.contentWindow.postMessage(
{
type: 'FILTER_CHANGE',
data: { filters: { region: 'North America' } },
},
'*',
);
// Data refresh
iframe.contentWindow.postMessage(
{
type: 'REFRESH_DATA',
},
'*',
);
// Custom events
iframe.contentWindow.postMessage(
{
type: 'CUSTOM_EVENT',
data: { action: 'highlight', value: 'top-performers' },
},
'*',
);
window.addEventListener('message', (event) => {
// Validate origin for security
if (event.origin !== 'https://your-domo-instance.domo.com') return;
switch (event.data.type) {
case 'CARD_CLICKED':
console.log('User clicked on card:', event.data);
break;
case 'DATA_UPDATED':
console.log('Card data updated:', event.data);
break;
case 'FILTER_APPLIED':
console.log('Filter was applied:', event.data);
break;
}
});
// Always validate message origins in production
if (event.origin !== 'https://your-domo-instance.domo.com') return;
<iframe
sandbox="allow-scripts allow-same-origin allow-forms allow-presentation"
src="{embedUrl}"
/>
Configure CSP headers to allow embedding from trusted Domo domains.
FILTER_CHANGE
: Apply filters to card dataREFRESH_DATA
: Trigger data refreshEXPORT_DATA
: Request data exportCARD_INIT
: Initial card configurationCUSTOM_EVENT
: Custom application events
CARD_LOADED
: Card finished loadingCARD_CLICKED
: User interaction with cardDATA_UPDATED
: Data source updatedFILTER_APPLIED
: Filter successfully appliedERROR
: Error occurred in card
- Update the message type constants
- Add handlers in the main App component
- Update the embedded card component if needed
- Add corresponding UI controls
- Modify SCSS files in each component directory
- Update global styles in
src/styles/
- Customize color scheme in
src/styles/variables.scss
-
Card not loading
- Verify card ID is correct
- Check Domo instance URL
- Ensure embedding is enabled for the card
-
Messages not being received
- Verify origin validation settings
- Check browser console for errors
- Ensure postMessage syntax is correct
-
CORS errors
- Configure proper CORS headers on Domo instance
- Verify iframe sandbox permissions
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
In the project directory, you can run:
Allows you to generate components or reducers.
Components
The command yarn generate component
will generate a new component and add it to the components folder of your project. There are 3 parameters to the component
generator that you will be prompted for if you do not provide them inline:
- Component Name
- Whether or not you would like to include a test file (y/n)
- Whether or not you would like to include a storybook file (y/n)
You can provide these parameters inline if you want: yarn generate component myComponent y n
or in part yarn generate component myComponent
. Any parameter that you do not provide will cause the plop generator to prompt you for an answer.
Reducers
The reducer generator only has one parameter, its name. You can generate a reducer using the command yarn generate reducer myReducer
. If you do not provide a name you will be prompted for one. Generating a reducer will produce the following modifications to your project:
- A new folder will be created in the actions directory of your project and an index.ts file will be added to it with some boiler plate examples of creating actions using Redux Toolkit.
- A new folder will be created in the reducers directory of your project and an index.ts file will be added to it with a basic reducer wired up with a default case. Handle new cases by adding `.addCase()` to the builder object provided. More info can be found in the Redux Toolkit documentation.
- The index.ts file in the base of the reducer folder will be modified to import your new reducer and wire it up. As long as you always create reducers using the generator command, you should never need to touch this file.
Runs the app in the development mode.
Open http://localhost:3000 to view it in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.
Launches the test runner in the interactive watch mode.
See the section about running tests for more information.
Builds the app for production to the build
folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
See the section about deployment for more information.
Starts up a storybook server to host any components that have been generated with a storybook file.
Note: this is a one-way operation. Once you eject
, you canโt go back!
If you arenโt satisfied with the build tool and configuration choices, you can eject
at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except eject
will still work, but they will point to the copied scripts so you can tweak them. At this point youโre on your own.
You donโt have to ever use eject
. The curated feature set is suitable for small and middle deployments, and you shouldnโt feel obligated to use this feature. However we understand that this tool wouldnโt be useful if you couldnโt customize it when you are ready for it.
You can learn more in the Create React App documentation.
To learn React, check out the React documentation.