From 485930b109f3e64200733692442eb4cc5acdb984 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Tue, 16 Jun 2026 13:33:59 +0100 Subject: [PATCH 1/4] Add POS shopify.printing API (getPrinters + printer selection) Introduces the `shopify.printing` API for the 2026-07 POS surface: - printing-api.ts: PrintingApi / PrintingApiContent with getPrinters() and print(src, options?), plus PrintOptions { printer?: Printer } and Printer { id, name, connected }. Mirrors the approved TAG spec (Shopify/ui-api-design#1413) and aligns with the WICG Web Printing model. - standard-api.ts: add PrintingApi to StandardApi. - api.ts: export the new public types. - print-api.ts: deprecate PrintApi / PrintApiContent in favor of shopify.printing. shopify.print remains as a deprecated alias; shopify.printing supersedes it. --- .changeset/pos-printing-api.md | 5 + .../src/surfaces/point-of-sale/api.ts | 7 ++ .../point-of-sale/api/print-api/print-api.ts | 4 + .../api/printing-api/printing-api.ts | 100 ++++++++++++++++++ .../api/standard/standard-api.ts | 2 + 5 files changed, 118 insertions(+) create mode 100644 .changeset/pos-printing-api.md create mode 100644 packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts diff --git a/.changeset/pos-printing-api.md b/.changeset/pos-printing-api.md new file mode 100644 index 0000000000..7fb1cd3a31 --- /dev/null +++ b/.changeset/pos-printing-api.md @@ -0,0 +1,5 @@ +--- +'@shopify/ui-extensions': minor +--- + +Add the POS `shopify.printing` API. `shopify.printing.getPrinters()` discovers hardware printers currently available to the device, and `shopify.printing.print(src, options?)` prints content fetched from a URL — opening the system print dialog by default, or sending directly to a printer when a `printer` (from `getPrinters()`) is passed via `options`. This supersedes `shopify.print`, which is now deprecated. diff --git a/packages/ui-extensions/src/surfaces/point-of-sale/api.ts b/packages/ui-extensions/src/surfaces/point-of-sale/api.ts index 59394033d5..a2d048d80a 100644 --- a/packages/ui-extensions/src/surfaces/point-of-sale/api.ts +++ b/packages/ui-extensions/src/surfaces/point-of-sale/api.ts @@ -65,6 +65,13 @@ export type { export type {PrintApi, PrintApiContent} from './api/print-api/print-api'; +export type { + PrintingApi, + PrintingApiContent, + PrintOptions, + Printer, +} from './api/printing-api/printing-api'; + export type { PaginationParams, ProductSortType, diff --git a/packages/ui-extensions/src/surfaces/point-of-sale/api/print-api/print-api.ts b/packages/ui-extensions/src/surfaces/point-of-sale/api/print-api/print-api.ts index 494cba2e16..f95ea29816 100644 --- a/packages/ui-extensions/src/surfaces/point-of-sale/api/print-api/print-api.ts +++ b/packages/ui-extensions/src/surfaces/point-of-sale/api/print-api/print-api.ts @@ -1,5 +1,7 @@ /** * The `PrintApi` object provides methods for triggering document printing. Access these methods through `shopify.print` to initiate print operations with various document types. + * + * @deprecated Use `shopify.printing` instead. The Printing API supersedes `shopify.print`, adding hardware printer discovery via `getPrinters()` and direct-to-printer printing via the `printer` option on `print()`. * @publicDocs */ export interface PrintApiContent { @@ -20,6 +22,8 @@ export interface PrintApiContent { /** * The `PrintApi` object provides methods for triggering document printing. Access these methods through `shopify.print` to initiate print operations with various document types. + * + * @deprecated Use `shopify.printing` instead. The Printing API supersedes `shopify.print`, adding hardware printer discovery via `getPrinters()` and direct-to-printer printing via the `printer` option on `print()`. * @publicDocs */ export interface PrintApi { diff --git a/packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts b/packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts new file mode 100644 index 0000000000..3510be1080 --- /dev/null +++ b/packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts @@ -0,0 +1,100 @@ +/** + * The Printing API provides methods for triggering document printing and + * discovering available hardware printers. Content is fetched from a URL + * and can be sent to a specific printer or to the system print dialog. + * + * Accessed via `shopify.printing`, aligning with the web platform's + * `navigator.printing` namespace from the WICG Web Printing proposal. + * + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/print | Window.print()} + * for the web platform equivalent (no parameters, prints current document). + * This API extends the concept with URL-based content and printer selection. + * @see {@link https://github.com/WICG/web-printing | WICG Web Printing} for the + * emerging web standard for printer enumeration and job submission. This API + * aligns with WICG's instance-level printer selection model. + * @publicDocs + */ +export interface PrintingApiContent { + /** + * Returns the list of hardware printers currently available to the + * device. Each printer includes its connection status and a reference + * that can be passed to `print()`. + * + * When no hardware printers are available, returns an empty array. + * The system print dialog is not included in this list — it is the + * default behavior when no `printer` option is provided to `print()`. + * + * @see {@link https://github.com/WICG/web-printing | WICG Web Printing} + * for the emerging web standard this aligns with. + * @returns A promise that resolves with the list of available hardware printers. + */ + getPrinters(): Promise; + + /** + * Triggers a print operation for the specified document source. + * + * When called without a `printer` option, opens the device's system + * print dialog (e.g., AirPrint on iOS, Android print service). When + * a `printer` reference is provided (from `getPrinters()`), sends + * the content directly to that printer without showing a dialog. + * + * The `src` parameter accepts either: + * - A relative path that will be appended to your app's [`application_url`](/docs/apps/build/cli-for-apps/app-configuration) + * - A full URL to your app's backend + * + * The content at the URL is fetched with the extension's session token + * for authentication. HTML, PDFs, and images are supported content types. + * + * @param src the source URL of the content to print. + * @param options optional configuration for the print operation. + * @returns A promise that resolves when the print job has been + * successfully sent. For hardware printers, this means the rasterized + * content has been dispatched — it does not wait for physical printing + * to complete. For the system print dialog, this resolves when the + * content is ready and the dialog appears. + * @throws {Error} when the content cannot be fetched from `src`. + * @throws {Error} when the specified `printer` is not connected. + */ + print(src: string, options?: PrintOptions): Promise; +} + +/** + * Options for `shopify.printing.print()`. + * @publicDocs + */ +export interface PrintOptions { + /** + * A printer reference obtained from `getPrinters()`. When provided, + * the print job is sent directly to this printer without showing + * a system print dialog. + * + * When omitted, the system print dialog is shown, allowing the + * user to select a printer and configure print settings. + */ + printer?: Printer; +} + +/** + * A hardware printer available to the device, as returned by `shopify.printing.getPrinters()`. + * @publicDocs + */ +export interface Printer { + /** Unique identifier for this printer. */ + id: string; + + /** Human-readable display name (e.g., "Star TSP143" or "Front Counter Printer"). */ + name: string; + + /** Whether the printer is currently able to accept print jobs. */ + connected: boolean; +} + +/** + * The `PrintingApi` object provides methods for triggering document printing + * and discovering available hardware printers. Access these methods through + * `shopify.printing`. + * @publicDocs + */ +export interface PrintingApi { + printing: PrintingApiContent; +} diff --git a/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts b/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts index 07bf167494..c481283a08 100644 --- a/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts +++ b/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts @@ -7,6 +7,7 @@ import {SessionApi} from '../session-api/session-api'; import {ToastApi} from '../toast-api/toast-api'; import {ProductSearchApi} from '../product-search-api/product-search-api'; import {PrintApi} from '../print-api/print-api'; +import {PrintingApi} from '../printing-api/printing-api'; import {StorageApi} from '../storage-api/storage-api'; import {PinPadApi} from '../pin-pad-api'; import type {I18n} from '../../../../api'; @@ -25,6 +26,7 @@ export type StandardApi = {[key: string]: any} & { ToastApi & SessionApi & PrintApi & + PrintingApi & ProductSearchApi & DeviceApi & ConnectivityApi & From 9d6b253f70e8e42d5ac21e60bbcac09ade16bc46 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Wed, 17 Jun 2026 09:32:06 +0100 Subject: [PATCH 2/4] Fix CI: opt out deprecation lint for retained PrintApi + add printing mock - standard-api.ts: PrintApi is intentionally kept in the StandardApi intersection so shopify.print keeps working as a deprecated alias of shopify.printing.print(). Suppress import/no-deprecated at the import and the intersection use (eslint runs with --max-warnings 0). - factories.ts: add the now-required `printing` property to the POS StandardApi test mock (getPrinters + print). Assisted-By: devx/8a5a23f1-0153-4f26-8b62-47e474da9689 --- packages/ui-extensions-tester/src/point-of-sale/factories.ts | 4 ++++ .../src/surfaces/point-of-sale/api/standard/standard-api.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/ui-extensions-tester/src/point-of-sale/factories.ts b/packages/ui-extensions-tester/src/point-of-sale/factories.ts index 6c538ee5cc..c65f76e2b8 100644 --- a/packages/ui-extensions-tester/src/point-of-sale/factories.ts +++ b/packages/ui-extensions-tester/src/point-of-sale/factories.ts @@ -131,6 +131,10 @@ function createMockStandardApi( deviceId: 1, }, print: {print: async () => {}}, + printing: { + getPrinters: async () => [], + print: async () => {}, + }, productSearch: { searchProducts: async () => ({items: [], hasNextPage: false}), fetchProductWithId: async () => undefined, diff --git a/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts b/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts index c481283a08..928b8576bc 100644 --- a/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts +++ b/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts @@ -6,6 +6,9 @@ import {LocaleApi} from '../locale-api/locale-api'; import {SessionApi} from '../session-api/session-api'; import {ToastApi} from '../toast-api/toast-api'; import {ProductSearchApi} from '../product-search-api/product-search-api'; +// `PrintApi` is deprecated but intentionally retained so `shopify.print` +// keeps working as an alias of `shopify.printing.print()`. +// eslint-disable-next-line import/no-deprecated import {PrintApi} from '../print-api/print-api'; import {PrintingApi} from '../printing-api/printing-api'; import {StorageApi} from '../storage-api/storage-api'; @@ -25,6 +28,7 @@ export type StandardApi = {[key: string]: any} & { LocaleApi & ToastApi & SessionApi & + // eslint-disable-next-line import/no-deprecated PrintApi & PrintingApi & ProductSearchApi & From e88740f0814be5447aebbbda0919053563c9dd50 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Fri, 19 Jun 2026 14:44:49 +0100 Subject: [PATCH 3/4] Document that printing a PDF to a selected printer throws Aligns the schema with the host-plugin behavior: receipt printers render HTML/image content only, so print(src, {printer}) with a PDF src throws. Adds the @throws entry and clarifies that PDFs print via the system dialog. Assisted-By: devx/8a5a23f1-0153-4f26-8b62-47e474da9689 --- .../surfaces/point-of-sale/api/printing-api/printing-api.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts b/packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts index 3510be1080..3ed54272d2 100644 --- a/packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts +++ b/packages/ui-extensions/src/surfaces/point-of-sale/api/printing-api/printing-api.ts @@ -44,6 +44,9 @@ export interface PrintingApiContent { * * The content at the URL is fetched with the extension's session token * for authentication. HTML, PDFs, and images are supported content types. + * PDFs can only be printed via the system print dialog: selecting a + * `printer` with a PDF `src` throws, because hardware (receipt) printers + * render HTML and image content only. * * @param src the source URL of the content to print. * @param options optional configuration for the print operation. @@ -54,6 +57,8 @@ export interface PrintingApiContent { * content is ready and the dialog appears. * @throws {Error} when the content cannot be fetched from `src`. * @throws {Error} when the specified `printer` is not connected. + * @throws {Error} when `src` is a PDF and a `printer` is selected, since + * receipt printers render HTML and image content only. */ print(src: string, options?: PrintOptions): Promise; } From 5c8368147306a1b332320fa229eb1aec93fe8e25 Mon Sep 17 00:00:00 2001 From: Aaron Schubert Date: Thu, 25 Jun 2026 11:19:39 -0400 Subject: [PATCH 4/4] Remove redundant comment on retained PrintApi alias import Assisted-By: devx/8a5a23f1-0153-4f26-8b62-47e474da9689 --- .../src/surfaces/point-of-sale/api/standard/standard-api.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts b/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts index 928b8576bc..83aad6da72 100644 --- a/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts +++ b/packages/ui-extensions/src/surfaces/point-of-sale/api/standard/standard-api.ts @@ -6,8 +6,6 @@ import {LocaleApi} from '../locale-api/locale-api'; import {SessionApi} from '../session-api/session-api'; import {ToastApi} from '../toast-api/toast-api'; import {ProductSearchApi} from '../product-search-api/product-search-api'; -// `PrintApi` is deprecated but intentionally retained so `shopify.print` -// keeps working as an alias of `shopify.printing.print()`. // eslint-disable-next-line import/no-deprecated import {PrintApi} from '../print-api/print-api'; import {PrintingApi} from '../printing-api/printing-api';