> ## Documentation Index
> Fetch the complete documentation index at: https://docs.superblocks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Interactive embedding

Once you have a basic embed set up, you can add interactive communication between the host app and Superblocks embedded app using **properties** and **events**:

* [**Properties**](#properties-pass-data-from-host-to-embed) - Send *reactive data* from the host app to the embedded app to update its state (e.g., pass search terms or selected filters, set dark or light mode)
* [**Events**](#events-two-way-communication) - Trigger *actions* bidirectionally from events in the host app or embedded app (e.g. scroll page of host app when button in embedded app is clicked, sync the URL path anytime page navigation happens in either the host or embedded app)

To implement any of these features, you'll need to add the necessary logic in your host app, and then prompt Clark to set up the embed interface in your Superblocks app.

## Properties - Pass data from host to embed

Send data to your embedded app to customize what users see based on properties of the host application. Properties are reactive—when they change in the host app, the embedded app automatically receives the updated values. Follow the steps below to get started working with properties.

<Steps>
  <Step title="Set properties in host app">
    In the host app, add logic for setting properties and passing them to the embed component.  For example, here the host app sets a `searchQuery` property to customize what the embed displays, along with `theme` property to toggle dark/light mode.

    <Accordion title="View code example" icon="code">
      <div style={{marginTop: '-1.25rem'}}>
        <CodeGroup>
          ```tsx React theme={null}
          import React, { useState } from 'react';
          import { SuperblocksEmbed } from '@superblocksteam/embed-react';

          const AppWithEmbed = () => {
              const [theme, setTheme] = useState('light');
              const [searchQuery, setSearchQuery] = useState('');

              const toggleTheme = () => {
                  setTheme(theme === 'light' ? 'dark' : 'light');
              };

              const properties = { theme, searchQuery };

              return (
                  <div>
                      {/* Theme toggle button */}
                      <button onClick={toggleTheme}>
                          Switch to {theme === 'light' ? 'dark' : 'light'} mode
                      </button>

                      {/* Search input */}
                      <input
                          type="text"
                          placeholder="Search..."
                          value={searchQuery}
                          onChange={(e) => setSearchQuery(e.target.value)}
                      />

                      {/* Embedded app receives properties reactively */}
                      <SuperblocksEmbed
                          src='https://app.superblocks.com/code-mode/embed/applications/<APP_ID>'
                          properties={properties}
                      />
                  </div>
              );
          };
          ```

          ```js JavaScript theme={null}
          let theme = 'light';
          let searchQuery = '';

          const sbApp = Superblocks.createSuperblocksEmbed({
              id: "sb-app",
              src: "https://app.superblocks.com/code-mode/embed/applications/<APP_ID>",
              properties: { theme, searchQuery },
          });
          document.body.appendChild(sbApp);

          // Toggle theme when button is clicked
          document.getElementById('theme-toggle').addEventListener('click', () => {
              theme = theme === 'light' ? 'dark' : 'light';
              sbApp.properties = { ...sbApp.properties, theme };
          });

          // Update search when input changes
          document.getElementById('search-input').addEventListener('input', (e) => {
              searchQuery = e.target.value;
              sbApp.properties = { ...sbApp.properties, searchQuery };
          });
          ```
        </CodeGroup>
      </div>
    </Accordion>
  </Step>

  <Step title="Prompt Clark to use properties in embedded app">
    Once you've set up properties in your host app, prompt Clark to use them in your Superblocks app. For example:

    > *This app will be embedded - Add support to accept a `searchQuery` property from the host app to filter the table, along with a `theme` property for toggling dark/light mode.*

    In the underlying code, Clark will import `useEmbedProperties` to read the specified properties and use them in the component logic (filtering, theming, etc.).

    <Accordion title="View code example" icon="code">
      <div style={{marginTop: '-1.25rem'}}>
        <CodeGroup>
          ```tsx App.tsx (theme) theme={null}
          // Apply theme at the root level to affect the entire app
          import { App as AppProvider, useEmbedProperties } from "@superblocksteam/library";
          import { Outlet } from "react-router";
          import { cn } from "./lib/utils";

          export default function AppComponent() {
              const embedProperties = useEmbedProperties();
              const theme = (embedProperties.theme as string) || "light";

              return (
                  <AppProvider className={cn("h-full w-full", theme === "dark" && "dark")}>
                      <main className="flex-1 h-full overflow-hidden">
                          <Outlet />
                      </main>
                  </AppProvider>
              );
          }
          ```

          ```tsx Page.tsx (searchQuery) theme={null}
          // Use in individual pages for filtering
          import { useEmbedProperties } from "@superblocksteam/library";

          export default function OrdersPage() {
              const embedProperties = useEmbedProperties();
              const searchQuery = (embedProperties.searchQuery as string) || "";

              // Filter data based on searchQuery from host app
              const filteredData = data.filter(item => 
                  item.name.toLowerCase().includes(searchQuery.toLowerCase())
              );

              return <Table data={filteredData} />;
          }
          ```
        </CodeGroup>
      </div>
    </Accordion>
  </Step>
</Steps>

## Events - Two-way communication

Use events for bidirectional communication between the host app and embedded Superblocks app.

| Direction        | Description                                                                            | Examples                                                                                                                                                                                |
| ---------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Embed → Host** | Notify the host application when something happens inside the embedded Superblocks app | • Notify the host when a user selects a row in a table<br />• Report errors or validation failures to the host<br />• Trigger navigation in the host app based on embed actions         |
| **Host → Embed** | Trigger actions inside the embedded Superblocks app from your host application         | • Trigger a data refresh when the user clicks a button in the host app<br />• Navigate to a specific view or record in the embedded app<br />• Open a modal or form in the embedded app |

Follow the steps below to get started working with events.

### Embed → Host

<Steps>
  <Step title="Add event listener in host app">
    Superblocks apps emit the following built-in events, which host apps can listen for:

    <div style={{marginLeft: '1rem'}}>
      | Event Name        | Handler        | Description                                                                                                                                                                                                                      |
      | ----------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
      | `AppLoadedEvent`  | `onAppLoaded`  | Triggered when the application finishes loading and becomes interactive.                                                                                                                                                         |
      | `AuthErrorEvent`  | `onAuthError`  | Triggered when the user's session expires or upon login if there is an authentication error. Will also trigger if the user clicks on a link that tries to bring them to a Superblocks Application they're not allowed to access. |
      | `NavigationEvent` | `onNavigation` | Triggered on cross application navigation events.                                                                                                                                                                                |
    </div>

    To respond to these events, register the relevant callback handler above in your host app's embed component.

    <Accordion title="View built-in event example" icon="code">
      <div style={{marginTop: '-1.25rem'}}>
        <CodeGroup>
          ```tsx React theme={null}
          import React from 'react';
          import { SuperblocksEmbed } from '@superblocksteam/embed-react';

          const AppWithEmbed = () => {
              const handleAuthError = (event) => {
                  console.log('User authentication with Superblocks failed');
              };

              return (
                  <SuperblocksEmbed
                      src='https://app.superblocks.com/code-mode/embed/applications/<APP_ID>'
                      onAuthError={handleAuthError}
                  />
              );
          };
          ```

          ```js JavaScript theme={null}
          async function handleAuthError(event) {
              console.log('User authentication with Superblocks failed');
          }

          const sbApp = document.getElementById("sb-app");
          sbApp.onAuthError = handleAuthError;
          ```
        </CodeGroup>
      </div>
    </Accordion>

    For any custom events emitted by your Superblocks app (see step 2), use the `onEvent` handler to listen and respond to these in your host app. Note, the `eventName` parameter is the name of the event emitted from Superblocks.

    <Accordion title="View custom event example" icon="code">
      <div style={{marginTop: '-1.25rem'}}>
        <CodeGroup>
          ```tsx React theme={null}
          import React from 'react';
          import { SuperblocksEmbed } from '@superblocksteam/embed-react';

          const AppWithEmbed = () => {
              const handleEvents = (eventName, payload) => {
                  switch (eventName) {
                      case 'removeCustomer': // Custom event name
                          console.log('Customer removed', payload.id);
                  }
              };

              return (
                  <SuperblocksEmbed
                      src='https://app.superblocks.com/code-mode/embed/applications/<APP_ID>'
                      onEvent={handleEvents}
                  />
              );
          };
          ```

          ```js JavaScript theme={null}
          // Handler for host app to respond to Superblocks events
          function handleEvent(eventName, payload) {
              if (eventName === "removeCustomer") {
                  console.log('Customer removed', payload.id);
              }
          }

          // Embed initialization
          const sbApp = Superblocks.createSuperblocksEmbed({
              id: "sb-app",
              src: "https://app.superblocks.com/code-mode/embed/applications/<APP_ID>",
              onEvent: handleEvent
          });

          document.body.appendChild(sbApp);
          ```
        </CodeGroup>
      </div>
    </Accordion>
  </Step>

  <Step title="Prompt Clark to emit custom events">
    For built-in events (`AppLoadedEvent`, `AuthErrorEvent`, `NavigationEvent`), no additional prompting is needed—your app emits these automatically.

    For custom events, prompt Clark to emit events for any actions in your app. For example:

    * *"Emit an orderSelected event when a user clicks a table row"*
    * *"Send a formSubmitted event to the host when the form is saved"*
    * *"Notify the host with an error event if the API call fails"*

    Clark will import `useEmitEmbedEvent` to call the emit function at the appropriate trigger point and include relevant payload data.

    <Accordion title="View code example" icon="code">
      <div style={{marginTop: '-1.25rem'}}>
        <CodeGroup>
          ```tsx Superblocks App theme={null}
          // Inside your Superblocks app
          import { useEmitEmbedEvent } from '@superblocksteam/embed-react';

          const OrderTable = () => {
              const emitEvent = useEmitEmbedEvent();

              const handleRowClick = (order) => {
                  // Emit event to the host app
                  emitEvent('orderSelected', {
                      orderId: order.id,
                      orderTotal: order.total,
                  });
              };

              const handleFormSubmit = async (formData) => {
                  try {
                      await saveOrder(formData);
                      emitEvent('formSubmitted', { success: true });
                  } catch (error) {
                      emitEvent('error', { message: error.message });
                  }
              };

              return (
                  <table>
                      {orders.map(order => (
                          <tr key={order.id} onClick={() => handleRowClick(order)}>
                              <td>{order.id}</td>
                              <td>{order.total}</td>
                          </tr>
                      ))}
                  </table>
              );
          };
          ```
        </CodeGroup>
      </div>
    </Accordion>
  </Step>
</Steps>

### Host → Embed

<Steps>
  <Step title="Emit event from host app">
    Use a ref to access the embed component and call `emit()` to send events to your Superblocks app.

    <Accordion title="View code example" icon="code">
      <div style={{marginTop: '-1.25rem'}}>
        <CodeGroup>
          ```tsx React theme={null}
          import { SuperblocksEmbed } from '@superblocksteam/embed-react';
          import { useRef } from 'react';

          const HostApp = () => {
              const embedRef = useRef(null);

              const handleRefreshClick = () => {
                  // Emit event to the embedded app
                  embedRef.current?.emit('refreshData', { timestamp: Date.now() });
              };

              const handleSelectOrder = (orderId) => {
                  embedRef.current?.emit('selectOrder', { orderId });
              };

              return (
                  <>
                      <button onClick={handleRefreshClick}>Refresh Data</button>
                      <button onClick={() => handleSelectOrder('order_456')}>
                          Select Order
                      </button>
                      <SuperblocksEmbed
                          ref={embedRef}
                          src='https://app.superblocks.com/code-mode/embed/applications/<APP_ID>'
                      />
                  </>
              );
          };
          ```

          ```js JavaScript theme={null}
          const sbApp = Superblocks.createSuperblocksEmbed({
              id: "sb-app",
              src: "https://app.superblocks.com/embed/applications/<APP_ID>",
          });
          document.body.appendChild(sbApp);

          // Emit event to the embedded app
          document.getElementById('refresh-btn').addEventListener('click', () => {
              sbApp.emit('refreshData', { timestamp: Date.now() });
          });

          document.getElementById('select-btn').addEventListener('click', () => {
              sbApp.emit('selectOrder', { orderId: 'order_456' });
          });
          ```
        </CodeGroup>
      </div>
    </Accordion>
  </Step>

  <Step title="Prompt Clark to listen for host events">
    Prompt Clark to add event listeners for any events you emit from the host app. For example:

    * *"Listen for a refreshData event from the host and refetch the API"*
    * *"When the host triggers selectOrder, highlight that row in the table"*
    * *"Add a listener for navigate\_to events to handle host-driven navigation"*

    Clark will import `useEmbedEvent`, register an event handler, and implement the action (refetch, select, navigate, etc.).

    <Accordion title="View code example" icon="code">
      <div style={{marginTop: '-1.25rem'}}>
        <CodeGroup>
          ```tsx Superblocks App theme={null}
          // Inside your Superblocks app
          import { useEmbedEvent } from '@superblocksteam/embed-react';

          const MyComponent = () => {
              const [selectedOrderId, setSelectedOrderId] = useState(null);

              // Listen for events from the host
              useEmbedEvent('refreshData', (payload) => {
                  console.log('Refreshing data...', payload.timestamp);
                  // Trigger API refetch
                  fetchData();
              });

              useEmbedEvent('selectOrder', (payload) => {
                  setSelectedOrderId(payload.orderId);
              });

              return <div>Selected: {selectedOrderId}</div>;
          };
          ```
        </CodeGroup>
      </div>
    </Accordion>
  </Step>
</Steps>

## Working with embedded apps in the Superblocks editor

Since embedded apps  often rely on host app information like properties, events, and logged-in user metadata, it can be helpful to simulate these in the Superblocks editor to review the app's look and functionality independent of embedding.

You can do this by prompting Clark to create a testing interface in the Superblocks editor—Clark is aware of the three modes of a Superblocks app (EDIT, PREVIEW, and PUBLISHED), so it is capable of writing conditional logic to show different components or execute different logic based on the mode of the app. For example:

> *Since this app is going to be embedded, I'd like to set up a way to simulate certain functionality directly in the Superblocks editor as follows:*
>
> <br />
>
> <br />
>
> *In EDIT mode:*
>
> * *Show a dropdown that allows me to select / assume a role (agent or manager)* to be used in the backend API
> * *Add a switch for toggling light / dark mode*
>
> <br />
>
> *In PREVIEW and PUBLISHED modes:*
>
> * *Don't show the dropdown—instead, get the role based on the logged-in user's `metadata.role`.*
> * *Dont show the toggle—instead get the mode based on a `theme` property passed from the host app*
