Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 52

Triggering Native Shopify UI with App Bridge

Recommended resources

Hello again! It's great to connect for our next lesson.

In our last session, we successfully built an embedded app page that could fetch product data from the Shopify API and even allow merchants to select products using the ResourcePicker. This was a huge step in building a full-stack slice of an app.

Today, we'll focus on polishing the user experience. A great app doesn't just perform tasks; it communicates clearly with the user. We'll explore how to provide feedback and create interactive dialogs using native Shopify UI elements. Your background in full-stack development will be helpful here, as this is analogous to creating front-end components that trigger server-side-styled UI responses, but with Shopify's specific toolset.

By the end of this lesson, you will be able to use App Bridge actions to trigger native Shopify UI elements like modals and toast messages.

Why Not Just Use alert() or a React Modal Library?

Your "first principles" approach to learning makes this a perfect place to start. Why do we need App Bridge for something as simple as a pop-up message? Why not use a standard library like react-modal or a simple alert()?

The answer lies in creating a seamless, native experience. Your app runs inside an <iframe> within the Shopify Admin.

  • A standard alert() is jarring and doesn't match the Shopify look and feel.
  • A modal from a generic React library would be trapped inside your app's <iframe>. It would be centered within your app's content area, not the entire Shopify Admin page, and the rest of the admin (like the main navigation) would remain active.

App Bridge solves this by acting as a "bridge" between your app and its host, the Shopify Admin. Your app sends a message (an "action") across this bridge, and the Shopify Admin itself renders the UI element.

Shopify App Bridge Dev Tools in Action
This GIF demonstrates the communication across App Bridge. The app on the left dispatches actions, and the App Bridge dev tools on theright show the Shopify Admin receiving these commands to update the UI.

To understand the benefits of this approach, please read the following section from the Shopify documentation.

Using modals in your app

The article 'Using modals in your app' explains the core reasons for using App Bridge for UI elements. It directly addresses the 'why' behind this pattern.

Please read the section titled 'Why App Bridge Modals instead of Polaris React Modals'. Focus on the three key benefits: Centering, Standardized header and footer, and Automatic updates.

This approach ensures that your app feels like an integrated part of Shopify, not a separate website embedded in a box.


Quick Feedback with Toast Messages

The simplest form of non-blocking feedback is a "toast" message. It's a small notification that appears briefly at the bottom of the screen to confirm an action or report a status.

Shopify App Bridge Toast Message Example
A toast message provides brief feedback to the user, like confirming that an action was successful.

Triggering a toast is a one-line command. Let's see it in action.

Getting Started with Shopify App Bridge - Create a Shopify App

The video 'Getting Started with Shopify App Bridge' from the WeeklyHow channel has a short, clear demonstration of how to trigger a toast message.

Watch the segment from 11:40 to 12:29. Notice how the global Shopify object is used in vanilla JavaScript. We will adapt this to the React useAppBridge hook that is standard in the Shopify CLI template.

In our React-based app, the implementation looks like this. We get the app instance from the useAppBridge hook and call the toast.show() method.

import { Page, Button } from "@shopify/polaris";
import { useAppBridge } from "@shopify/app-bridge-react";

export default function ToastExample() {
  const app = useAppBridge();

  const showSuccessToast = () => {
    app.toast.show("Changes saved successfully!");
  };

  const showErrorToast = () => {
    app.toast.show("Failed to save changes", {
      isError: true,
      duration: 5000, // Show for 5 seconds
    });
  };

  return (
    <Page>
      <Button onClick={showSuccessToast}>Show Success Toast</Button>
      <Button onClick={showErrorToast}>Show Error Toast</Button>
    </Page>
  );
}

The toast.show() method is straightforward: the first argument is the message, and the second is an optional options object where you can control its duration and style (e.g., isError: true).


Focused Interaction with Modals

When you need to get the user's full attention—for a confirmation dialog, a form, or a resource selector—you'll use a modal. As we discussed, App Bridge modals feel native because the Shopify Admin renders them outside your app's <iframe>.

There are two primary ways to create and manage modals.

Method 1: Declarative Modal with Imperative Trigger

This is the most common pattern. You define the modal's structure in your JSX and then open it with a function call.

  1. Define the Modal: Use the <Modal> and <TitleBar> components from @shopify/app-bridge-react. Give the modal a unique id.
  2. Trigger the Modal: Use app.modal.show('your-modal-id') from an event handler, like a button's onClick.

The video you'll watch next demonstrates this pattern by creating a modal and then adding a title bar and buttons.

Getting Started with Shopify App Bridge - Create a Shopify App

Let's return to the 'Getting Started with Shopify App Bridge' video. This section provides a practical walkthrough of creating a modal.

Watch from 14:11 to 17:20. Pay attention to how a ui-modal web component is first created with an ID, and then triggered by calling Shopify.modal.show() with that same ID. The example also shows how to add a title bar and buttons, building a complete interactive element.

Let's look at a complete, practical example in React for a confirmation dialog. This is a pattern you will use constantly as a freelancer.

import { Page, Button } from "@shopify/polaris";
import { Modal, TitleBar, useAppBridge } from "@shopify/app-bridge-react";

export default function ConfirmationModalExample() {
  const app = useAppBridge();

  const handleDelete = () => {
    console.log("Deletion confirmed!");
    app.modal.hide("confirm-delete-modal");
    app.toast.show("Item deleted.");
  };

  return (
    <Page>
      {/* The button that opens the modal */}
      <Button destructive onClick={() => app.modal.show("confirm-delete-modal")}>
        Delete Item
      </Button>

      {/* The Modal definition */}
      <Modal id="confirm-delete-modal">
        <p>This action cannot be undone. Are you sure you want to proceed?</p>
        <TitleBar title="Confirm deletion">
          <button variant="primary" tone="critical" onClick={handleDelete}>
            Delete
          </button>
          <button onClick={() => app.modal.hide("confirm-delete-modal")}>
            Cancel
          </button>
        </TitleBar>
      </Modal>
    </Page>
  );
}

Notice how we use app.modal.hide('confirm-delete-modal') to close the modal programmatically.

Method 2: Controlled Modal with the open Prop

Alternatively, you can control the modal's visibility using React state, just like you would with any other React component. This is useful when the modal's visibility is tied to your application's state rather than a direct, one-off action.

For a detailed look at this and other modal configurations, the Shopify developer documentation is an excellent resource.

Modal Component

The 'Modal Component' API documentation provides a great set of code examples for various use cases. It's a perfect reference for practical implementation.

First, review the example under 'Showing a Modal with the open prop'. This demonstrates how to bind the modal's visibility to a React state variable (modalOpen). Then, look at the example under 'Subscribing to Hide'. This shows the onHide callback, which is useful for cleaning up state when the user closes the modal (e.g., by pressing the Escape key).

Here's how the state-controlled pattern looks:

import { Page, Button } from "@shopify/polaris";
import { Modal, TitleBar } from "@shopify/app-bridge-react";
import { useState } from "react";

export default function ControlledModalExample() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <Page>
      <Button onClick={() => setIsOpen(true)}>Open Modal</Button>

      <Modal open={isOpen} onHide={() => setIsOpen(false)}>
        <p>This modal is controlled by React state.</p>
        <TitleBar title="Controlled Modal">
          <button variant="primary" onClick={() => setIsOpen(false)}>
            Close
          </button>
        </TitleBar>
      </Modal>
    </Page>
  );
}
Test your understanding!

You need to build a feature where clicking a "Settings" button opens a complex form. The form has its own state and logic. When would you choose the app.modal.show('id') method versus the state-controlled open={isOpen} method?

Show answer

For a complex form, the state-controlled open={isOpen} method is generally better.

The reason is that the form's lifecycle (mounting and unmounting) becomes tied to the isOpen state. When isOpen is true, the modal and its form content will mount, allowing you to fetch data or initialize state in a useEffect. When isOpen becomes false, the modal unmounts, automatically cleaning up its state.

The app.modal.show() method is better for simple, stateless modals like a quick confirmation dialog, where you don't need to manage a complex component lifecycle.


Conclusion

In this lesson, we learned how to create a polished and professional user experience by providing clear feedback through native Shopify UI elements. By using App Bridge actions, we ensure our app feels deeply integrated with the Shopify Admin.

Key Takeaways:

  • App Bridge is essential for triggering native UI elements like toasts and modals to maintain a consistent UX.
  • Toasts, triggered by app.toast.show(), are used for simple, non-blocking notifications.
  • Modals are for focused, blocking interactions and can be created in two main ways:
    1. Defined with the <Modal id="..."> component and triggered imperatively with app.modal.show('...').
    2. Controlled declaratively using React state and the open prop on the <Modal> component.
  • The choice between these modal patterns depends on the complexity of the modal's content and state.

In our next lesson, we will shift our focus from the admin to the storefront. You will learn about Theme App Extensions, a powerful mechanism that allows your app to inject functionality and UI elements directly into a merchant's online store theme. This is a critical skill for building many types of Shopify apps.