Modal
Modals are overlays that prevent merchants from interacting with the rest of the app until a specific action is taken.
Modals can be disruptive because they require merchants to take an action before they can continue interacting with the rest of Shopify. As such, modals should be used thoughtfully and sparingly.
The Modal
action set allows you to open two types of modal: message and iframe. Message modals support only plain text content. Iframe modals allow you to fully customize the modal contents.
Setup
Create an app and import the Modal
module from @shopify/app-bridge/actions
. Note that we'll be referring to this sample application throughout the examples below.
import createApp from '@shopify/app-bridge';
import {Modal} from '@shopify/app-bridge/actions';
const app = createApp({
apiKey: '12345',
shopOrigin: shopOrigin,
});
Create a message modal
Create a message modal using the message
option. Message modals support plain text content of any length using the message
option.
const modalOptions = {
title: 'My Modal',
message: 'Hello world!',
};
const myModal = Modal.create(app, modalOptions);
Create an iframe modal
Create an iframe modal by passing the url
option. If the url
option is present, then the message
option will be ignored.
Create an iframe modal with an absolute URL
const modalOptions = {
title: 'My Modal',
url: 'http://example.com',
};
const myModal = Modal.create(app, modalOptions);
Create an iframe modal with a relative path
A relative path iframe sets the URL relative to your app root.
const modalOptions = {
title: 'My Modal',
path: '/settings',
};
const myModal = Modal.create(app, modalOptions);
If your app’s root URL was https://myapp.com
, then the example above would open a modal at https://myapp.com/settings
.
Open and close a modal
Open and close the modal by dispatching the OPEN
and CLOSE
actions.
const modalOptions = {
title: 'My Modal',
url: 'http://example.com',
};
const myModal = Modal.create(app, modalOptions);
myModal.dispatch(Modal.Action.OPEN);
// Close modal
myModal.dispatch(Modal.Action.CLOSE);
Add footer buttons
You can add buttons to the modal footer. All modals support one primary button and multiple secondary buttons. To learn more about buttons, refer to Button.
const okButton = Button.create(app, {label: 'Ok'});
okButton.subscribe(Button.Action.CLICK, () => {
// Do something with the click action
});
const cancelButton = Button.create(app, {label: 'Cancel'});
cancelButton.subscribe(Button.Action.CLICK, () => {
// Do something with the click action
});
const modalOptions = {
title: 'My Modal',
message: 'Hello world!',
footer: {
buttons: {
primary: okButton,
secondary: [cancelButton],
},
},
};
const myModal = Modal.create(app, modalOptions);
Subscriptions
You can subscribe to modal actions by calling subscribe
. This returns a function that you can call to unsubscribe from the action:
const modalOptions = {
title: 'My Modal',
url: 'http://example.com',
};
const myModal = Modal.create(app, modalOptions);
const openUnsubscribe = myModal.subscribe(Modal.Action.OPEN, () => {
// Do something with the open event
});
const closeUnsubscribe = myModal.subscribe(Modal.Action.CLOSE, () => {
// Do something with the close event
});
// Unsubscribe to actions
openUnsubscribe();
closeUnsubscribe();
All action sets in App Bridge support the same subscribe API. The modal footer buttons also return an unsubscribe function.
const okButton = Button.create(app, {label: 'Ok'});
const okButtonUnsubscribe = okButton.subscribe(Button.Action.CLICK, () => {
// Do something with the click action
});
okButtonUnsubscribe();
Unsubscribe from all
You can call unsubscribe
to remove all subscriptions on the modal and its children (including buttons):
const okButton = Button.create(app, {label: 'Ok'});
okButton.subscribe(Button.Action.CLICK, () => {
// Do something with the click action
});
const cancelButton = Button.create(app, {label: 'Cancel'});
cancelButton.subscribe(Button.Action.CLICK, () => {
// Do something with the click action
});
const modalOptions = {
title: 'My Modal',
url: 'http://example.com',
footer: {
buttons: {
primary: okButton,
secondary: [cancelButton],
},
},
};
const myModal = Modal.create(app, modalOptions);
myModal.subscribe(Modal.Action.OPEN, () => {
// Do something with the open event
});
myModal.subscribe(Modal.Action.CLOSE, () => {
// Do something with the close event
});
// Unsubscribe from modal open and close actions
// Unsubscribe from okButton and cancelButton click actions
myModal.unsubscribe();
Unsubscribe from modal actions only
You can call unsubscribe
with false
to remove only modal subscriptions while leaving child subscriptions intact. For example, you might want to unsubscribe from the modal but keep button listeners so that the buttons can be reused in a different modal.
const okButton = Button.create(app, {label: 'Ok'});
okButton.subscribe(Button.Action.CLICK, () => {
// Do something with the click action
});
const cancelButton = Button.create(app, {label: 'Cancel'});
cancelButton.subscribe(Button.Action.CLICK, () => {
// Do something with the click action
});
const modalOptions = {
title: 'My Modal',
message: 'Hello world!',
footer: {
buttons: {
primary: okButton,
secondary: [cancelButton],
},
},
};
const myModal = Modal.create(app, modalOptions);
// Unsubscribe only from modal open and close actions
myModal.unsubscribe(false);
// The buttons above can be reused in a new modal
// Their subscriptions will be left intact
const newModalOptions = {
title: 'Confirm',
message: 'Are you sure?',
footer: {
buttons: {
primary: okButton,
secondary: [cancelButton],
},
},
};
const confirmModal = Modal.create(app, newModalOptions);
Update options
You can call the set
method with partial modal options to update the options of an existing modal. This automatically triggers the update
action on the modal and merges the given options with the existing options.
const modalOptions = {
title: 'My Modal',
url: 'http://example.com',
};
const myModal = Modal.create(app, modalOptions);
myModal.set({title: 'My new title'});
Update footer buttons
You can update buttons attached to a modal's footer. Any updates made to the modal's footer buttons automatically trigger an update
action on the modal:
const okButton = Button.create(app, {label: 'Ok'});
const cancelButton = Button.create(app, {label: 'Cancel'});
const modalOptions = {
title: 'My Modal',
message: 'Hello world!',
footer: {
buttons: {
primary: okButton,
secondary: [cancelButton],
},
},
};
const myModal = Modal.create(app, modalOptions);
myModal.dispatch(Modal.Action.OPEN);
okButton.set({label: 'Good to go!'});
Set modal size
By default, modals have a fixed size of Small
. You can customize the size of a modal by passing in a different Modal.Size
value:
const modalOptions = {
title: 'My Modal',
message: 'Hello world!',
size: Modal.Size.Large,
};
const myModal = Modal.create(app, modalOptions);
myModal.dispatch(Modal.Action.OPEN);
There are 3 values for Modal.Size
: Small
, Medium
and Large
.
Set modal size automatically
The setupModalAutoSizing
utility allows your iframe modal to update its height to fit the page content.
In your main app, open an iframe modal:
import createApp from '@shopify/app-bridge';
import {Modal} from '@shopify/app-bridge/actions';
import {setupModalAutoSizing} from '@shopify/app-bridge-utils';
const app = createApp({
apiKey: '12345',
});
const modalOptions = {
title: 'My Modal',
path: '/modal',
};
const myModal = Modal.create(app, modalOptions);
myModal.dispatch(Modal.Action.OPEN);
Inside the modal page, import the setupModalAutoSizing
utility to enable auto sizing:
import createApp from '@shopify/app-bridge';
import {setupModalAutoSizing} from '@shopify/app-bridge-utils';
const app = createApp({
apiKey: '12345',
});
setupModalAutoSizing(app);
Avoid setting height
, margin
or padding
styles on the <body>
element of your modal page, as these will interfere with automatic modal sizing. As a workaround, set these styles on a wrapper element instead.
If you are using Shopify Polaris, be aware that it applies height: 100%
to the <body>
element by default. You will need to override this style on your modal page.
Communicate with the parent page
It’s often useful for a modal to be able to communicate with its parent page. You can use the DATA
action to send messages between an iframe modal and its parent app.
To send data from a modal, dispatch a Modal.Action.DATA
action from your modal:
import createApp from '@shopify/app-bridge';
import {Modal} from '@shopify/app-bridge/actions';
const app = createApp({
apiKey: '12345',
});
const payload = {
message: 'Hi this is modal!'
};
app.dispatch(Modal.data(payload));
In your app, subscribe to Modal.Action.DATA
:
import createApp from '@shopify/app-bridge';
import {Modal} from '@shopify/app-bridge/actions';
const app = createApp({
apiKey: '12345',
});
app.subscribe(Modal.Action.DATA, (action) => {
console.log('Received message from modal:', action);
});
To send data from the app to the modal, complete the steps in reverse: subscribe to Modal.Action.DATA
in the modal and dispatch a Modal.Action.DATA
action from your app.