Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
dc15766
Add POS List web component types
ajanth-u Sep 1, 2026
67ca32c
Add POS List generated docs data
ajanth-u Sep 1, 2026
40dddf1
Use standard POS list click details
ajanth-u Sep 1, 2026
5c6633c
Document POSList subtitle color and chevron defaults
ajanth-u Sep 1, 2026
d145625
Add per-row clickable control to POSList
ajanth-u Sep 2, 2026
afc2556
Switch POSList types to per-row onClick callbacks
ajanth-u Sep 2, 2026
5d1e677
Pass a click event to POSList row callbacks
ajanth-u Sep 2, 2026
88491b6
Update POSList example callbacks to log events
ajanth-u Sep 2, 2026
706ce1d
Document toggle switch precedence over trailing label and chevron
ajanth-u Sep 10, 2026
6b8fd34
Type POSListRow.onClick with the plain click event the host sends
ajanth-u Sep 10, 2026
2501fd5
Document that a disabled POSList toggle switch blocks row activation
ajanth-u Sep 10, 2026
cb567ea
Document that POSList auto image display is decided per row
ajanth-u Sep 10, 2026
438e7ff
Use the s-text and s-badge vocabulary for POSList subtitles and badges
ajanth-u Sep 10, 2026
31619b2
Narrow POSList tone and color off BadgeProps and TextProps
ajanth-u Sep 10, 2026
dee1d8a
Replace per-row onClick with a list-level rowclick event
ajanth-u Sep 11, 2026
d3d8ac3
Document that POSList rowclick listener errors are not reported by POS
ajanth-u Sep 11, 2026
081f69a
Publish POSList tone and color as literal unions
ajanth-u Sep 11, 2026
6e40114
Drop the auto POSList row type; rows are buttons by default
ajanth-u Sep 11, 2026
822fcbb
Make a POSList row end either trailing text or a toggle switch
ajanth-u Sep 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pos-list-component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/ui-extensions': minor
---

Add the `s-pos-list` web component for structured, incrementally loaded POS lists.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -137,6 +138,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -257,6 +259,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -379,6 +382,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -501,6 +505,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -623,6 +628,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -745,6 +751,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -827,6 +834,7 @@
"Modal",
"NumberField",
"POSBlock",
"POSList",
"Page",
"PosBlock",
"Route",
Expand Down Expand Up @@ -1644,6 +1652,18 @@
"pos.register-details.block.render"
]
},
"POSList": {
"targets": [
"pos.cart.line-item-details.action.render",
"pos.customer-details.action.render",
"pos.draft-order-details.action.render",
"pos.home.modal.render",
"pos.order-details.action.render",
"pos.product-details.action.render",
"pos.purchase.post.action.render",
"pos.register-details.action.render"
]
},
"Page": {
"targets": [
"pos.cart.line-item-details.action.render",
Expand Down
233 changes: 233 additions & 0 deletions packages/ui-extensions/src/surfaces/point-of-sale/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5416,6 +5416,175 @@ declare module 'preact' {
}
}

declare const posListTagName = 's-pos-list';
type POSListImageDisplayStrategy = 'auto' | 'always' | 'never';
type POSListRowSubtitle =
| string
| {
/** The subtitle text. */
content: string;
/**
* The semantic meaning of the subtitle, as on `s-text`.
*
* @default 'auto'
*/
tone?:
| 'auto'
| 'neutral'
| 'info'
| 'success'
| 'warning'
| 'critical'
| 'caution';
/**
* The emphasis of the subtitle, as on `s-text`. A value other than `base` overrides `tone`.
*
* @default 'base'
*/
color?: 'base' | 'strong' | 'subdued';
};
type POSListBadge = {
/** The badge text. */
text: string;
/**
* The semantic meaning of the badge, as on `s-badge`.
*
* @default 'auto'
*/
tone?:
| 'auto'
| 'neutral'
| 'info'
| 'success'
| 'warning'
| 'critical'
| 'caution';
};
type POSListRowImage = {
/** The URL of the image displayed at the start of the row. */
src?: string;
/** A numeric badge displayed over the image. */
badge?: number;
};
type POSListToggleSwitch = {
/**
* The current state of the toggle switch.
*
* @default false
*/
checked?: boolean;
/**
* Whether the toggle switch is disabled.
*
* A disabled toggle switch also blocks activation of its row, so the row doesn't fire `rowclick`.
*
* @default false
*/
disabled?: boolean;
};
type POSListRowStart = {
/** The primary text for the row. */
label: string;
/** Up to three lines of supporting text displayed below the label. */
subtitles?: [POSListRowSubtitle, POSListRowSubtitle?, POSListRowSubtitle?];
/** Status or category badges displayed with the row content. */
badges?: POSListBadge[];
/** The image displayed at the start of the row. */
image?: POSListRowImage;
};
type POSListRowEnd =
| {
/** Supporting text displayed at the end of the row. */
label?: string;
/**
* Whether to display a chevron at the end of the row.
*
* @default false
*/
showChevron?: boolean;
toggleSwitch?: never;
}
| {
label?: never;
showChevron?: never;
/** A toggle switch displayed at the end of the row, in place of trailing text and chevron. */
toggleSwitch: POSListToggleSwitch;
};
/**
* The event fired when a row is activated. `detail.id` is the `id` of the activated row.
* Errors thrown or promises rejected in the listener stay in the extension; POS does not report them.
*/
type POSListRowClickEvent = CallbackEvent<typeof posListTagName> & {
detail: {id: string};
};
type POSListRow = {
/** A unique identifier for the row. */
id: string;
/** The primary content displayed at the start of the row. */
start: POSListRowStart;
/**
* What the row is.
*
* - `button`: Activating the row fires `rowclick`.
* - `text`: Static content that can't be activated.
*
* @default 'button'
*/
type?: 'text' | 'button';
/** Optional content displayed at the end of the row. */
end?: POSListRowEnd;
};
/**
* Displays structured rows with text, badges, images, and optional trailing content.
*
* @publicDocs
*/
interface POSListJSXProps {
/** A unique identifier for the element. */
id?: string;
/**
* The rows displayed in the list.
*
* @default []
*/
rows?: POSListRow[];
/**
* Controls whether rows reserve space for images.
*
* - `auto`: Displays an image only on rows that include an image source; other rows reserve no space.
* - `always`: Displays images or placeholders for every row.
* - `never`: Displays rows without images or image placeholders.
*
* @default 'auto'
*/
imageDisplayStrategy?: POSListImageDisplayStrategy;
/**
* Whether additional rows are being loaded.
*
* @default false
*/
loadingMore?: boolean;
/** Callback when a row is activated. `event.detail.id` identifies the row. */
onRowClick?: ((event: POSListRowClickEvent) => void) | null;
/** Callback when more rows should be loaded. */
onLoadMore?: ((event: CallbackEvent<typeof posListTagName>) => void) | null;
/** Content displayed before the rows as part of the list's scrollable content. */
header?: ComponentChild;
}
type POSListElementProps = Omit<POSListJSXProps, 'header'>;
declare global {
interface HTMLElementTagNameMap {
[posListTagName]: HtmlElementTagNameProps<POSListElementProps>;
}
}
declare module 'preact' {
namespace createElement.JSX {
interface IntrinsicElements {
[posListTagName]: IntrinsicElementProps<POSListElementProps>;
}
}
}

export type {
BadgeJSXProps,
BannerJSXProps,
Expand All @@ -5438,6 +5607,7 @@ export type {
ModalJSXProps,
NumberFieldJSXProps,
PageJSXProps,
POSListJSXProps,
PosBlockJSXProps,
QrCodeJSXProps,
ScrollBoxJSXProps,
Expand All @@ -5458,6 +5628,54 @@ export type {
TimePickerJSXProps,
};

/**
* Events emitted by the POS list.
* @publicDocs
*/
interface POSListEvents {
/** Fired when a row is activated. `event.detail.id` identifies the row. */
rowclick?: (event: POSListRowClickEvent) => void;
/** Fired when more rows should be loaded. */
loadmore?: (event: CallbackEvent<typeof posListTagName>) => void;
}

/**
* Content slots for the POS list.
* @publicDocs
*/
interface POSListSlots {
/** Content displayed before the rows as part of the list's scrollable content. */
header?: HTMLElement;
}

/**
* Displays structured rows with text, badges, images, and optional trailing content.
* @publicDocs
*/
interface POSList {
/** A unique identifier for the element. */
id?: string;
/**
* The rows displayed in the list.
* @default []
*/
rows?: POSListRow[];
/**
* Controls whether rows reserve space for images.
*
* - `auto`: Displays an image only on rows that include an image source; other rows reserve no space.
* - `always`: Displays images or placeholders for every row.
* - `never`: Displays rows without images or image placeholders.
* @default 'auto'
*/
imageDisplayStrategy?: POSListImageDisplayStrategy;
/**
* Whether additional rows are being loaded.
* @default false
*/
loadingMore?: boolean;
}

/**
* The link component provides event callbacks for handling user interactions. Learn more about [handling events](/docs/api/polaris/using-polaris-web-components#handling-events).
* @publicDocs
Expand Down Expand Up @@ -7771,3 +7989,18 @@ declare global {
}
}
}

declare module 'react' {
namespace JSX {
interface IntrinsicElements {
[posListTagName]: IntrinsicElementProps<POSListElementProps>;
}
}
}
declare global {
namespace JSX {
interface IntrinsicElements {
[posListTagName]: IntrinsicElementProps<POSListElementProps>;
}
}
}
Loading
Loading