Shopify UI Extensions
repository·2026-10-rc·Indexed 43 days ago
https://github.com/shopify/ui-extensionsPublic definition of Shopify's UI extension API for building strongly-typed, sandboxed UI modules. Includes the @shopify/ui-extensions-tester for testing extensions with Vitest, featuring mock Shopify globals, fetch and navigation mocks, and surface-specific helpers for Admin and Checkout targets (API version 2025-10 or later).
What's inside Shopify UI Extensions
- The Standard Admin API is the interface used to build UI extensions for the Shopify Admin. It provides the necessary primitives and hooks to interact with the Admin environment, allowing developers to render custom UI components and access relevant data within the Shopify Admin interface.
What are @shopify/ui-extensions and which surfaces do they support?
2026-10-rcThe
@shopify/ui-extensionspackage provides the public type definitions and utilities required to build Shopify UI extensions.Extensions are built using a unified underlying technology (Remote DOM) and share a common set of core components (such as
s-block,s-button, ands-text-field) and capabilities (such as session tokens and direct API access).While the core technology is shared, APIs and components are partitioned by surface to ensure developers only see what is relevant to their specific context. Supported surfaces include:
- Admin
- Customer account
- POS (Point of Sale)
- Checkout
When to use the Button component
2026-10-rcThe
Buttoncomponent should be used for performing actions within the checkout flow. Common use cases include:- Add
- Continue
- Pay now
- Save
Using
Buttoninstead of aLinkfor these actions provides a larger hit area and follows standard accessibility patterns for functional triggers.How NPM deployment is triggered
2026-10-rcNPM deployment is automated via GitHub Actions. When changeset files are detected on a stable version or RC branch, a GitHub action creates a PR that:
- Merges all unpublished changesets into a single changelog.
- Increments the version numbers of the updated packages.
Once this PR is reviewed and merged by a member of the UI Extension Stewards GitHub team, the new package versions are automatically published to NPM. Packages are tagged with their API version, allowing users to install specific versions via:
yarn add @shopify/ui-extensions@2023-01Test extension code that relies on signals
2026-10-rcThe mock Shopify API does not implement working signals. To test logic that depends on signal changes (like
shopify.lines.value), you must test the interaction and the state change separately:- Test the interaction: Trigger the event (e.g., a button click) and verify that the correct mutation function was called with the expected arguments.
- Test the rendering: Manually update the mock signal value (e.g.,
extension.shopify.lines.value = [...]) and callextension.render()to verify the UI reflects the new state.
import {createCartLine} from '@shopify/ui-extensions-tester/checkout'; // 1. Test the interaction test('increments cart line quantity on click', async () => { const line = createCartLine(); extension.shopify.lines.value = [line]; const applyCartLinesChange = vi.spyOn(extension.shopify, 'applyCartLinesChange'); await extension.render(); const button = document.body.querySelector('s-button')!; fireEvent.click(button); await waitFor(() => { expect(applyCartLinesChange).toHaveBeenCalledWith({ type: 'updateCartLine', id: line.id, quantity: line.quantity + 1, }); }); }); // 2. Test the rendering of the new state test('it renders the cart line quantity', async () => { extension.shopify.lines.value = [createCartLine({quantity: 2})]; await extension.render(); const text = document.body.querySelector('s-text')!; expect(text.textContent).toContain('2'); });Set up the extension test harness
2026-10-rcYou must create a harness to manage the lifecycle of the
shopifyglobal and the DOM. There are two ways to do this:1. Using
using(Recommended for Node ≥ 22.0.0)Use
setUpExtensionwith theusingkeyword for automatic setup and teardown via Explicit Resource Management.2. Classic Setup
Use
getExtensionand manually manage the lifecycle with Vitest'sbeforeEachandafterEachhooks.setUp()creates the mockshopifyglobal, andtearDown()clears the DOM and the global.// Option 1: Automatic teardown (Node 22+) import {setUpExtension} from '@shopify/ui-extensions-tester'; test('rendering the extension', async () => { using extension = setUpExtension('purchase.checkout.block.render'); await extension.render(); }); // Option 2: Manual lifecycle import {getExtension} from '@shopify/ui-extensions-tester'; import {beforeEach, afterEach} from 'vitest'; const extension = getExtension('purchase.checkout.block.render'); beforeEach(() => extension.setUp()); afterEach(() => extension.tearDown());How extension points and registration work
2026-10-rcAn extension system is constructed by mapping specific "extension points" (identified by unique string names) to third-party code.
The Registration Lifecycle
- Configuration: You define your target extension point in a
shopify.ui.extension.tomlfile. - Registration: When your extension script is loaded, Shopify automatically calls
shopify.extend()to register your code for that specific extension point. - Execution: The host application calls a
run()function, passing in the public API (such as data and a UIroot) which is then forwarded to your extension's callback.
Implementation Pattern
In your extension code, you typically use a helper function (like
extensions()) as a default export. This implicitly handles the registration and execution logic.- Configuration: You define your target extension point in a
How UI Extensions work technically
2026-10-rcUI Extensions are built on remote-ui, an open-source technology that uses a message-passing system to communicate between the extension and the host application.
Key technical characteristics:
- Component Model: Extensions render components that are represented as minimal JavaScript objects rather than actual DOM elements. These objects are sent to the host application, which renders them into native UI.
- Decoupled Rendering: Because extensions do not render to the DOM, Shopify can update or change the underlying native components without requiring extension developers to update their code. This also enables seamless merchant theming (e.g., in Shopify Checkout).
- Framework Bindings: remote-ui provides integrations for frameworks like React and Vue, allowing developers to use familiar syntax while the underlying communication remains via remote-ui.
What are UI extensions?
2026-10-rcA UI extension is a JavaScript-based module that hooks into client-side behaviors on Shopify's first-party UI surfaces. Extensions are configured via a
shopify.extension.tomlfile and consist of three core properties:name: The name presented to merchants.target: A string identifier describing the specific UI surface and responsibility where the extension should inject itself (e.g.,purchase.checkout.cart-line-item.render-after).module: The local JavaScript module that contains the logic to render the UI.
UI extensions are built on
remote-dom, which enables rendering native UI elements within a safe sandbox. Eachtargetprovides a specific set of available UI Components (and their properties) and imperative APIs (for reading/writing data relevant to that specific surface).Mock App Home and App Intent targets
2026-10-rcWhen testing specific admin targets, the mock environment provides pre-configured objects:
admin.app.home.render: Includesshopify.toast,shopify.app,shopify.loading(),shopify.tools, andshopify.intents.request.admin.app.intent.render: Includesshopify.intents.response.ok(),.error(), and.closed().
Related components for text and headings
2026-10-rcWhen building layouts with headings, you may need these related components to manage hierarchy and text styling:
HeadingGroup: Use this to control the heading level (e.g., H1, H2, H3) for all nested headings within the group.Text: Use this to provide semantic value and specific styling for individual pieces of text content.TextBlock: Use this to render blocks of text that should occupy the full available width, such as paragraphs.
How UI extension versioning works
2026-10-rcShopify UI extensions use a versioned API system. New stable versions are released quarterly at the beginning of each quarter (months
01,04,07, or10) using theYYYY-MMformat.Release Lifecycle
- Stable Versions (
YYYY-MM): These are the official releases. Only bugfixes (patchchanges) should be merged into stable branches. - Release Candidates (
YYYY-MM-rc): Created alongside a new stable version to preview upcoming features. Active development happens here. Packages published from these branches use a{{SEMVER}}-rc.{{VERSION}}format (e.g.,2025.10.0-rc.5). - Unstable (Deprecated): The
unstablebranch is frozen at2025-07and should not be used for new work. Always branch off the latest RC branch instead.
- Stable Versions (