Add React and Vue ShopifyAccountWidget bindings
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.1k
- Forks
- 443
- Avg merge
- 4d 19h
- Merged PRs (30d)
- 24
Description
Parent
- #4005
Context
The framework-neutral renderer from the previous issue defines the HTML and SSR contract for Shopify's account widget. React and Vue users should receive idiomatic bindings that hide Shopify's element hierarchy, slot assignment, event wiring and CSP-safe layout styles.
The <shopify-account> Storefront Web Component renders a customer-account avatar. When selected, it opens Shopify's account sheet with sign-in options or signed-in customer links.
The signed-out avatar must be explicit and required. Broad React children and Vue default-slot APIs make its purpose unclear and allow an empty SSR fallback by accident.
Proposed APIs
React uses a required prop:
<ShopifyAccountWidget
storeDomain={storeDomain}
publicAccessToken={publicAccessToken}
customerAccessToken={customerAccessToken}
signedOutAvatar={
<img src="/account.svg" width={44} height={44} alt="" />
}
onOpen={handleOpen}
onClose={handleClose}
/>
Vue uses an explicit required named slot rather than its broad default slot:
<ShopifyAccountWidget
:store-domain="storeDomain"
:public-access-token="publicAccessToken"
:customer-access-token="customerAccessToken"
@open="handleOpen"
@close="handleClose"
>
<template #signed-out-avatar>
<img src="/account.svg" width="44" height="44" alt="" />
</template>
</ShopifyAccountWidget>
Both bindings should render the supplied content inside one Hydrogen-owned wrapper with slot="signed-out-avatar". Consumers must not add the native slot attribute themselves.
Event behaviour
Shopify dispatches open and close as non-bubbling CustomEvents from <shopify-account>.
- React must attach listeners directly with
addEventListener()so the binding works with both React 18 and React 19. - Vue must listen on the underlying
<shopify-account>and re-emit framework events from the wrapper component. - Listeners must be updated and removed when handlers or component lifecycles change.
Acceptance criteria
- Export
ShopifyAccountWidgetand its prop types from@shopify/hydrogen/react. - Export the equivalent component and types from
@shopify/hydrogen/vue. - React requires
signedOutAvatar: ReactElement; it does not usechildrenfor the avatar. - Vue requires an explicit
signed-out-avatarnamed slot; it does not use the default slot. - Both bindings add
slot="signed-out-avatar"through a stable Hydrogen-owned wrapper. - The bindings render the shared core structure and nonce-bearing stylesheet without copying attribute, default or CSS knowledge.
- The bindings do not require
className, user CSS or inlinestyleattributes for layout stability. - Documentation requires visual-only avatar content. It must not include links, buttons or other focusable elements because Shopify projects it inside its own button.
- React exposes
onOpenandonCloseand listens directly on the custom element using native event listeners. - Vue exposes
openandcloseevents and listens directly on the custom element. - Event tests verify the documented event object, listener replacement and cleanup.
- Changing, adding or removing
customerAccessTokencauses the widget to reflect the new signed-in state. If Shopify does not observe the store attribute, deliberately remount the custom element and test that behaviour. - SSR and hydration complete without mismatches, including when a CSP nonce is present.
- Tests cover required-avatar typing, avatar placement, events, hydration and customer-token changes.
- Replace the React Router template's raw
renderShopifyAccountWidget()integration with the React binding without changing its rendered behaviour. - Update the Customer Account skill and public documentation with core, React and Vue examples.
- Documentation explains that
ShopifyScripts accountWidgetis still required. - Add a minor changeset.
Out of scope
- Broad React
childrenor Vue default-slot content. - Requiring consumers to provide
slot="signed-out-avatar". - Interactive content inside the signed-out avatar.
- Styling or replacing Shopify's account sheet internals.
- Implementing authentication or account pages.
Blocked by
- #4007
References
<shopify-account>events and slotspackages/hydrogen/src/react/shop-pay.tsxpackages/hydrogen/src/vue/shop-pay.tspackages/hydrogen/skills/hydrogen-customer-account/SKILL.md
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
This work is blocked by #4007 and builds on the framework-neutral renderer from #4005. Start by reading packages/hydrogen/src/react/shop-pay.tsx, packages/hydrogen/src/vue/shop-pay.ts, and packages/hydrogen/skills/hydrogen-customer-account/SKILL.md, then locate the React Router template integration. Done means both bindings, exports, event and token-change tests, SSR/hydration coverage, documentation, the template migration, and a minor changeset are complete.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- documentation, frontend, testing
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100