--- title: "Embedded analytics SDK - components" --- # Embedded analytics SDK - questions {% include beta-blockquote.html %} {% include plans-blockquote.html feature="Embedded analytics SDK" sdk=true %} There are different ways you can embed questions: - [Static question](#embedding-a-static-question). Embeds a chart. Clicking on the chart doesn't do anything. - [Interactive question](#embedding-an-interactive-question). Clicking on the chart gives you the drill-through menu. - [Query builder](#embedding-the-query-builder). Embeds the graphical query builder without a pre-defined query. ## Embedding a static question You can embed a static question using the `StaticQuestion` component. The component has a default height, which can be customized by using the `height` prop. To inherit the height from the parent container, you can pass `100%` to the height prop. ```typescript import React from "react"; import {MetabaseProvider, StaticQuestion} from "@metabase/embedding-sdk-react"; const config = {...} export default function App() { const questionId = 1; // This is the question ID you want to embed return ( <MetabaseProvider config={config}> <StaticQuestion questionId={questionId} showVisualizationSelector={false}/> </MetabaseProvider> ); } ``` You can pass parameter values to questions defined with SQL via `parameterValues` prop, in the format of `{parameter_name: parameter_value}`. Learn more about [SQL parameters](../../questions/native-editor/sql-parameters.md). ```jsx {% raw %} <StaticQuestion questionId={questionId} parameterValues={{ product_id: 50 }} /> {% endraw %} ``` ## Embedding an interactive question You can embed an interactive question using the `InteractiveQuestion` component. ```typescript import React from "react"; import {MetabaseProvider, InteractiveQuestion} from "@metabase/embedding-sdk-react"; const config = {...} export default function App() { const questionId = 1; // This is the question ID you want to embed return ( <MetabaseProvider config={config}> <InteractiveQuestion questionId={questionId}/> </MetabaseProvider> ); } ``` ## Question props | Prop | Type | Description | | ------------------ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | questionId | number or string | (required) The ID of the question. This is either:<br>- The numerical ID when accessing a question link, e.g., `http://localhost:3000/question/1-my-question` where the ID is `1`.<br>- The `entity_id` key of the question object. You can find a question's entity ID in the info panel when viewing a question. | | plugins | `{ mapQuestionClickActions: Function }` or null | Additional mapper function to override or add drill-down menu. | | height | number or string | (optional) A number or string specifying a CSS size value that specifies the height of the component | | entityTypeFilter | string array; options include "table", "question", "model", "metric" | (optional) An array that specifies which entity types are available in the data picker | | isSaveEnabled | boolean | (optional) Whether people can save the question. | | withResetButton | boolean | (optional, default: `true`) Determines whether a reset button is displayed. Only relevant when using the default layout | | withTitle | boolean | (optional, default: `false`) Determines whether the question title is displayed. Only relevant when using the default layout. | | customTitle | string or undefined | (optional) Allows a custom title to be displayed instead of the default question title. Only relevant when using the default layout. | | onBeforeSave | `() => void` | (optional) A callback function that triggers before saving. Only relevant when `isSaveEnabled = true`. | | onSave | `() => void` | (optional) A callback function that triggers when a user saves the question. Only relevant when `isSaveEnabled = true`. | | saveToCollectionId | number | (optional) The target collection to save the question to. This will hide the collection picker from the save modal. Only applicable to static questions. | ## Customizing interactive questions By default, the Embedded analytics SDK provides a default layout for interactive questions that allows you to view your questions, apply filters and aggregations, and access functionality within the query builder. Here's an example of using the `InteractiveQuestion` component with its default layout: ```typescript <InteractiveQuestion questionId={95} /> ``` To customize the layout, use namespaced components within the `InteractiveQuestion` component. For example: ```typescript {% raw %} <InteractiveQuestion questionId={95}> <div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", }} > <div style={{ display: "grid", placeItems: "center" }}> <InteractiveQuestion.Title /> <InteractiveQuestion.ResetButton /> </div> <div style={{ display: "flex", alignItems: "center", justifyContent: "flex-start", overflow: "hidden", }} > <div style={{ width: "100%" }}> <InteractiveQuestion.QuestionVisualization /> </div> <div style={{ display: "flex", flex: 1, overflow: "scroll" }}> <InteractiveQuestion.Summarize /> </div> </div> <div style={{ display: "flex", flexDirection: "column" }}> <InteractiveQuestion.Filter /> </div> </div> </InteractiveQuestion> {% endraw %} ``` ## Interactive question components These components are available via the `InteractiveQuestion` namespace (e.g., `<InteractiveQuestion.Filter />`). | Component | Info | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `BackButton` | The back button, which provides `back` functionality for the InteractiveDashboard | | `FilterBar` | The row of badges that contains the current filters that are applied to the question | | `Filter` | The Filter pane containing all possible filters | | `FilterButton` | The button used in the default layout to open the Filter pane. You can replace this button with your own implementation. | | `ResetButton` | The button used to reset the question after the question has been modified with filters/aggregations/etc | | `Title` | The question's title | | `SaveButton` | Button for saving the question. | | `Summarize` | The Summarize pane containing all possible aggregations | | `SummarizeButton` | The button used in the default layout to open the Summarize pane. You can replace this button with your own implementation. | | `Notebook` | The Notebook editor that allows for more filter, aggregation, and custom steps | | `NotebookButton` | The button used in the default layout to open the Notebook editor. You can replace this button with your own implementation. | | `QuestionVisualization` | The chart visualization for the question | | `QuestionSettings` | The settings for the current visualization | ## Interactive question plugins You can use plugins to add custom functionality to your questions. ### `mapQuestionClickActions` This plugin allows you to add custom actions to the click-through menu of an interactive question. You can add and customize the appearance and behavior of the custom actions. ```typescript // You can provide a custom action with your own `onClick` logic. const createCustomAction = clicked => ({ buttonType: "horizontal", name: "client-custom-action", section: "custom", type: "custom", icon: "chevronright", title: "Hello from the click app!!!", onClick: ({ closePopover }) => { alert(`Clicked ${clicked.column?.name}: ${clicked.value}`); closePopover(); }, }); // Or customize the appearance of the custom action to suit your need. const createCustomActionWithView = clicked => ({ name: "client-custom-action-2", section: "custom", type: "custom", view: ({ closePopover }) => ( <button className="tw-text-base tw-text-yellow-900 tw-bg-slate-400 tw-rounded-lg" onClick={() => { alert(`Clicked ${clicked.column?.name}: ${clicked.value}`); closePopover(); }} > Custom element </button> ), }); const plugins = { /** * You will have access to default `clickActions` that Metabase renders by default. * So you could decide if you want to add custom actions, remove certain actions, etc. */ mapQuestionClickActions: (clickActions, clicked) => { return [ ...clickActions, createCustomAction(clicked), createCustomActionWithView(clicked), ]; }, }; const questionId = 1; // This is the question ID you want to embed return ( <MetabaseProvider config={config} pluginsConfig={plugins}> <InteractiveQuestion questionId={questionId} /> </MetabaseProvider> ); ``` ## Embedding an editable interactive question You can edit an existing question using the query builder by passing the `isSaveEnabled` prop on the `InteractiveQuestion` component. ```tsx import React from "react"; import {MetabaseProvider, InteractiveQuestion} from "@metabase/embedding-sdk-react"; const config = {...} export default function App() { return ( <MetabaseProvider config={config}> <InteractiveQuestion questionId={1} isSaveEnabled /> </MetabaseProvider> ); } ``` ## Embedding the query builder With the `CreateQuestion` component, you can embed the query builder without a pre-defined question. ```tsx import React from "react"; import {MetabaseProvider, CreateQuestion} from "@metabase/embedding-sdk-react"; const config = {...} export default function App() { return ( <MetabaseProvider config={config}> <CreateQuestion/> </MetabaseProvider> ); } ```