Skip to content

[5/7] Add s-pos-list web component types and the posListTemplate compiler - #4690

Open
ajanth-u wants to merge 1 commit into
2026-10-rcfrom
au/pos-list-template-2026-10
Open

ajanth-u wants to merge 1 commit into
2026-10-rcfrom
au/pos-list-template-2026-10

Conversation

@ajanth-u

@ajanth-u ajanth-u commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

What

Adds <s-pos-list> for POS API version 2026-10 and the posListTemplate tagged template that compiles its row markup. This is the templated candidate for GSD #51755; the legacy-parity alternative is #4661 (unmodified, held as contingency). Exactly one of the two should merge.

Companion PRs: World #2061117 (ui-api-design contract), #2061112 → #2061124 → #2061132 (pos-mobile host stack), Shopify/pos-e2e-ui-extension (sandbox screen, follows), World shopify-dev docs (follows).

Design

rows is plain data ({id, templateFor, ...fields}) and itemTemplates is a compiled AST produced once in the extension bundle by posListTemplate:

const itemTemplates = posListTemplate`
  <s-pos-list-item templateId="section-header" type="text">
    <s-heading>{{title}}</s-heading>
  </s-pos-list-item>
  <s-pos-list-item templateId="product">
    <s-stack direction="inline">
      <s-image src="{{image.src}}" alt="{{name}}" />
      <s-text>{{name}}</s-text>
      {{#if onSale}}<s-badge tone="success">Sale</s-badge>{{/if}}
      <s-switch bind:checked="active" />
    </s-stack>
  </s-pos-list-item>
`;
<s-pos-list rows={rows} itemTemplates={itemTemplates} onRowClick={(e) => e.detail.item.id} />

POS hydrates one template copy per FlashList-mounted row, so no extension code runs while scrolling and no functions cross the bridge (no Shopify/extensibility change needed).

Output is stamped with this package's API version (version: '2026-10'); POS renders templates only for an extension declaring the same API version and reports a mismatch by name (itemTemplates were compiled for API version X but this extension runs API version Y).

Grammar: {{path}} in text; {{path}} inside an attribute (always a string); bind:prop="path" (the only typed binding); {{#if path}}…{{/if}} (no nesting, no else). Compilation and validation happen when the helper executes, not during the extension build. Define templates at module scope to compile once per module execution. Rejected by the helper with posListTemplate:-prefixed errors: on* attributes (including bind:onClick), ${} interpolation of any kind, #each/other expressions, nested/unbalanced #if (including nesting through component children), #if inside an attribute, text directly under <s-pos-list-item>, non-item roots, nested s-pos-list-item/s-pos-list, missing/duplicate templateId, unknown type, any other root attribute.

Changes

  • src/surfaces/point-of-sale/pos-list-template.ts — the compiler (htm-based; htm becomes a direct dependency).
  • src/surfaces/point-of-sale.ts — exports posListTemplate plus POSListTemplateTag, POSListTemplates, POSListItemTemplate, POSListTemplateNode, POSListTemplateProp, POSListTemplateSegment, POSListRow, POSListRowClickEvent.
  • components/POSList.d.ts (generated from pos-mobile meta.ts via pnpm build-extension-components:publish 2026-10, with the generator fixes from World #2061112) and the POSList blocks merged into components.d.ts. POSListRowClickEvent carries {item, index} in detail, the only event field POS's RemoteDOM bridge forwards to an extension; the ui-api-design contract (World #2061117) declares item/index on the event, and POS exposes them once the bridge forwards custom event properties. POSListTemplates.version is the compiling API version string (`${number}-${number}` | 'unstable'). Only POSList additions are included; the pre-existing drift between the generator output and this repo's components.d.ts/components-shared.d.ts is left alone.
  • components/targets/StandardComponents.ts| 'POSList'.
  • components/POSList/examples/{default,incremental-loading}.jsx.
  • docs/.../2026-10/{generated_docs_data_v2.json,targets.json} regenerated with build-docs.mjs 2026-10.
  • .changeset/pos-list-template-component.md (minor).

Verification

  • yarn build, yarn type-check green; build/esm/surfaces/point-of-sale.mjs exports posListTemplate.
  • loom test packages/ui-extensions/src/surfaces/point-of-sale/tests/pos-list-template — 19 tests: exact AST output for text placeholders, {{#if}} blocks, bind:, attribute segments, valueless attributes, type="text"; and every rejection above with its literal message.
  • eslint clean on the changed files.

Co-authored by AI.

@ajanth-u

Copy link
Copy Markdown
Collaborator Author

/snapit

@shopify-github-actions-access

Copy link
Copy Markdown
Contributor

🫰✨ Thanks @ajanth-u! Your snapshots have been published to npm.

Test the snapshots by updating your package.json with the newly published versions:

"@shopify/ui-extensions": "0.0.0-snapshot-20260912150820",
"@shopify/ui-extensions-tester": "0.0.0-snapshot-20260912150820"

@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from 5a59c47 to 5104cfa Compare September 14, 2026 12:49
@ajanth-u

Copy link
Copy Markdown
Collaborator Author

/snapit

@shopify-github-actions-access

Copy link
Copy Markdown
Contributor

🫰✨ Thanks @ajanth-u! Your snapshots have been published to npm.

Test the snapshots by updating your package.json with the newly published versions:

"@shopify/ui-extensions": "0.0.0-snapshot-20260914125004",
"@shopify/ui-extensions-tester": "0.0.0-snapshot-20260914125004"

@ajanth-u ajanth-u changed the title [POS] Add s-pos-list and the posListTemplate compiler (2026-10) [5/7] Add s-pos-list web component types and the posListTemplate compiler Sep 14, 2026
@ajanth-u
ajanth-u marked this pull request as ready for review September 14, 2026 13:38
@ajanth-u ajanth-u self-assigned this Sep 14, 2026
@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from 5104cfa to ab76ca7 Compare September 14, 2026 14:07
@ajanth-u

Copy link
Copy Markdown
Collaborator Author

/snapit

@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from ab76ca7 to 6277775 Compare September 14, 2026 17:00
@shopify-github-actions-access

Copy link
Copy Markdown
Contributor

🫰✨ Thanks @ajanth-u! Your snapshots have been published to npm.

Test the snapshots by updating your package.json with the newly published versions:

"@shopify/ui-extensions": "0.0.0-snapshot-20260914170119",
"@shopify/ui-extensions-tester": "0.0.0-snapshot-20260914170119"

@ajanth-u

Copy link
Copy Markdown
Collaborator Author

/snapit

@shopify-github-actions-access

Copy link
Copy Markdown
Contributor

🫰✨ Thanks @ajanth-u! Your snapshots have been published to npm.

Test the snapshots by updating your package.json with the newly published versions:

"@shopify/ui-extensions": "0.0.0-snapshot-20260914174215",
"@shopify/ui-extensions-tester": "0.0.0-snapshot-20260914174215"

@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from 6277775 to 1008f3a Compare September 14, 2026 21:06
@ajanth-u

Copy link
Copy Markdown
Collaborator Author

/snapit

@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from 1008f3a to 74f5cd9 Compare September 14, 2026 22:31
@shopify-github-actions-access

Copy link
Copy Markdown
Contributor

🫰✨ Thanks @ajanth-u! Your snapshots have been published to npm.

Test the snapshots by updating your package.json with the newly published versions:

"@shopify/ui-extensions": "0.0.0-snapshot-20260914223154",
"@shopify/ui-extensions-tester": "0.0.0-snapshot-20260914223154"

@ajanth-u

Copy link
Copy Markdown
Collaborator Author

/snapit

@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from 74f5cd9 to ab8a211 Compare September 15, 2026 00:14
@shopify-github-actions-access

Copy link
Copy Markdown
Contributor

🫰✨ Thanks @ajanth-u! Your snapshots have been published to npm.

Test the snapshots by updating your package.json with the newly published versions:

"@shopify/ui-extensions": "0.0.0-snapshot-20260915001551",
"@shopify/ui-extensions-tester": "0.0.0-snapshot-20260915001551"

@ajanth-u

Copy link
Copy Markdown
Collaborator Author

/snapit

@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from ab8a211 to 25c0861 Compare September 15, 2026 20:34
@shopify-github-actions-access

Copy link
Copy Markdown
Contributor

🫰✨ Thanks @ajanth-u! Your snapshots have been published to npm.

Test the snapshots by updating your package.json with the newly published versions:

"@shopify/ui-extensions": "0.0.0-snapshot-20260915203520",
"@shopify/ui-extensions-tester": "0.0.0-snapshot-20260915203520"

`<s-pos-list>` renders a virtualized list whose rows are plain data
(`rows`) and whose markup comes from item templates (`itemTemplates`)
compiled in the extension bundle by the `posListTemplate` tagged template.
POS hydrates one template copy per mounted row, so lists of thousands of
rows stay responsive and no extension code runs while scrolling.

Templates are static `<s-pos-list-item templateId="…" type="button|text">`
roots. Inside them `{{path}}` interpolates a row field as text,
`bind:prop="path"` passes a row field to a component prop with its own
type, and `{{#if path}}…{{/if}}` renders its content when the field is
truthy. Event handlers, interpolated values, nested `#if`, `#each`, text
directly under the root, and any other `{{…}}` expression are rejected at
compile time with a `posListTemplate:` prefixed error.

The compiled output is stamped with this package's API version
(`2026-10`); POS renders templates only for an extension declaring the
same API version, so bundling a package that does not match the
extension's `api_version` is reported by name instead of rendering
unexpectedly.

The component types are generated from POS Mobile's `meta.ts` and merged
into `components.d.ts`; `POSList` joins `StandardComponents`; the POS docs
data for 2026-10 is regenerated. `htm` (already a transitive dependency of
several surfaces) becomes a direct dependency for the parser.

Assisted-By: devx/058a962b-6514-4c8e-a49e-37b8e478fe36
@ajanth-u
ajanth-u force-pushed the au/pos-list-template-2026-10 branch from 25c0861 to 3b107e3 Compare September 16, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant