Skip to main content

Modal

The modal component displays content in an overlay. Use to create a distraction-free experience such as a confirmation dialog or a settings panel.

A button triggers the modal using the commandFor attribute. Content within the modal scrolls if it exceeds available height.


Configure the following properties on the modal component.

string
required

A label that describes the purpose of the modal. When set, it will be announced to users using assistive technologies and will provide them with more context.

This overrides the heading prop for screen readers.

string
required

A title that describes the content of the modal.

"base" | "none"
Default: 'base'
required

Adjust the padding around the modal content.

base: applies padding that is appropriate for the element.

none: removes all padding from the element. This can be useful when elements inside the modal need to span to the edge of the modal. For example, a full-width image. In this case, rely on box with a padding of 'base' to bring back the desired padding for the rest of the content.

"small" | "small-100" | "base" | "large" | "large-100"
Default: 'base'
required

The size of the modal component, controlling its width and height. Larger sizes provide more space for content while smaller sizes are more compact.

() => void
required

A method to programmatically show the overlay.

() => void
required

A method to programmatically hide the overlay.

() => void
required

A method to programmatically toggle the visibility of the overlay.

The modal component provides event callbacks for handling user interactions. Learn more about handling events.

Anchor to afterhide
afterhide
<typeof tagName> | null
required

A callback fired after the modal is hidden.

Anchor to aftershow
aftershow
<typeof tagName> | null
required

A callback fired after the modal is shown.

<typeof tagName> | null
required

A callback fired when the modal is hidden.

<typeof tagName> | null
required

A callback fired when the modal is shown.

The modal component supports slots for additional content placement within the component. Learn more about using slots.

Anchor to children
children
HTMLElement

The content displayed within the modal component, typically including form fields, information, or interactive elements.

Anchor to primary-action
primary-action
HTMLElement

The main action button displayed in the modal footer, representing the primary action users should take.

Only accepts a single button component with a variant of primary. This action should align with the modal's main purpose.

Anchor to secondary-actions
secondary-actions
HTMLElement

Additional action buttons displayed in the modal footer, providing alternative or supporting actions.

Only accepts button components with a variant of secondary or auto. These are visually de-emphasized to establish clear hierarchy.


Anchor to Confirm a merchant actionConfirm a merchant action

Focus merchant attention on a critical decision before proceeding. This example presents a delete confirmation with cancel and confirm buttons.

Preview

html

<s-button commandFor="modal">Open</s-button>

<s-modal id="modal" heading="Details">
<s-paragraph>Displaying more details here.</s-paragraph>

<s-button slot="secondary-actions" commandFor="modal" command="--hide">
Close
</s-button>
<s-button
slot="primary-action"
variant="primary"
commandFor="modal"
command="--hide"
>
Save
</s-button>
</s-modal>

Anchor to Show information in a modalShow information in a modal

Present information that needs merchant acknowledgment. This example displays a simple announcement with a heading and body text.

Preview

html

<s-button commandFor="info-modal" command="--show">Show product info</s-button>

<s-modal id="info-modal" heading="Product information">
<s-text>This product is currently out of stock and cannot be ordered.</s-text>

<s-button slot="secondary-actions" commandFor="info-modal" command="--hide">
Close
</s-button>
</s-modal>

Anchor to Confirm an action with buttonsConfirm an action with buttons

Provide clear choices with action buttons in the modal footer. This example pairs primary and secondary buttons for confirming or canceling.

Preview

html

<s-stack gap="base">
<s-button tone="critical" commandFor="delete-modal" command="--show">
Delete product
</s-button>

<s-modal id="delete-modal" heading="Delete product?">
<s-stack gap="base">
<s-text>Are you sure you want to delete "Winter jacket"?</s-text>
<s-text tone="caution">This action cannot be undone.</s-text>
</s-stack>

<s-button
slot="primary-action"
variant="primary"
tone="critical"
commandFor="delete-modal"
command="--hide"
>
Delete product
</s-button>
<s-button
slot="secondary-actions"
variant="secondary"
commandFor="delete-modal"
command="--hide"
>
Cancel
</s-button>
</s-modal>
</s-stack>

Anchor to Collect input with a formCollect input with a form

Gather information without leaving the current context. This example embeds a feedback form with text inputs and a submit button.

Preview

html

<s-stack gap="base">
<s-button variant="primary" commandFor="edit-modal" command="--show">
Edit customer
</s-button>

<s-modal id="edit-modal" heading="Edit customer information" size="large">
<s-stack gap="base">
<s-text-field
label="Customer name"
name="name"
value="Sarah Johnson"
></s-text-field>

<s-email-field
label="Email address"
name="email"
value="sarah@example.com"
></s-email-field>

<s-text-field
label="Phone number"
name="phone"
value="+1 555-0123"
></s-text-field>

<s-select label="Customer group" name="group">
<s-option value="retail">Retail</s-option>
<s-option value="wholesale" selected>Wholesale</s-option>
<s-option value="vip">VIP</s-option>
</s-select>
</s-stack>

<s-button
slot="primary-action"
variant="primary"
commandFor="edit-modal"
command="--hide"
>
Save changes
</s-button>
<s-button
slot="secondary-actions"
variant="secondary"
commandFor="edit-modal"
command="--hide"
>
Cancel
</s-button>
</s-modal>
</s-stack>

Adjust modal width to match your content needs. This example demonstrates small, base, and large size variations.

Preview

html

<s-stack gap="base">
<s-stack direction="inline" gap="base">
<s-button commandFor="small-modal" command="--show">Small modal</s-button>
<s-button commandFor="large-modal" command="--show">Large modal</s-button>
</s-stack>

<!-- Small modal for quick confirmations -->
<s-modal id="small-modal" heading="Confirm action" size="small-100">
<s-text>Are you sure you want to proceed?</s-text>
<s-button
slot="primary-action"
variant="primary"
commandFor="small-modal"
command="--hide"
>
Confirm
</s-button>
<s-button
slot="secondary-actions"
variant="secondary"
commandFor="small-modal"
command="--hide"
>
Cancel
</s-button>
</s-modal>

<!-- Large modal for detailed content -->
<s-modal id="large-modal" heading="Order details" size="large-100">
<s-stack gap="base">
<s-section>
<s-heading>Order #1001</s-heading>
<s-text>Placed on March 15, 2024</s-text>
</s-section>

<s-divider></s-divider>

<s-section>
<s-heading>Items</s-heading>
<s-stack gap="small">
<s-text>Winter jacket - $89.99</s-text>
<s-text>Wool scarf - $29.99</s-text>
<s-text>Leather gloves - $45.99</s-text>
</s-stack>
</s-section>

<s-divider></s-divider>

<s-text type="strong">Total: $165.97</s-text>
</s-stack>

<s-button
slot="primary-action"
variant="primary"
commandFor="large-modal"
command="--hide"
>
Close
</s-button>
</s-modal>
</s-stack>

Anchor to Display full-width contentDisplay full-width content

Display media or tables that need full-width space. This example sets the padding property to false for edge-to-edge content.

Preview

html

<s-stack gap="base">
<s-button commandFor="image-modal" command="--show">
View product image
</s-button>

<s-modal id="image-modal" heading="Product image" padding="none">
<s-box background="subdued" padding="base">
<s-text>Image would display here with full width</s-text>
</s-box>

<s-button
slot="secondary-actions"
variant="secondary"
commandFor="image-modal"
command="--hide"
>
Close
</s-button>
</s-modal>
</s-stack>

Anchor to Delete with async handlingDelete with async handling

Safely handle destructive operations with proper feedback. This example implements loading states, error handling, and async confirmation.

Preview

html

<s-button tone="critical" commandFor="delete-modal">Delete product</s-button>

<s-modal id="delete-modal" heading="Delete product?">
<s-text>This will permanently delete "Blue T-Shirt". This action cannot be undone.</s-text>

<s-button slot="secondary-actions" commandFor="delete-modal" command="--hide">Cancel</s-button>
<s-button slot="primary-action" variant="primary" tone="critical" id="confirm-delete">
Delete product
</s-button>
</s-modal>

<script>
const modal = document.getElementById('delete-modal');
const deleteBtn = document.getElementById('confirm-delete');

deleteBtn.addEventListener('click', async () => {
deleteBtn.loading = true;
try {
await fetch('/api/products/123', { method: 'DELETE' });
modal.hideOverlay();
// Show success feedback to merchant
} catch (error) {
// Handle error - show error message
} finally {
deleteBtn.loading = false;
}
});
</script>

  • Use for focused, specific tasks that require merchants to make a decision or acknowledge critical information.
  • Include a prominent and clear call to action.
  • Don't nest modals (avoid launching one modal from another).
  • Use specific action verbs: Label buttons with clear verbs like "Delete", "Save", or "Continue" rather than vague terms like "Yes", "OK", or "Submit".
  • For destructive actions, explain the consequences in the modal body.
  • Use thoughtfully and sparingly—don't create unnecessary interruptions.
  • Use as a last resort for important decisions, not for contextual tools or actions that could happen on the page directly.

  • Modals can only be opened by user interaction, not programmatically on page load.
  • The modal always renders centered in the viewport and cannot be repositioned.
  • Content within the modal scrolls if it exceeds the available height.

Was this page helpful?