port-widget
Port or introduce an InstantSearch widget or connector-driven feature across this monorepo's JavaScript, React, and Vue flavors. Use when the task is to add a missing wrapper around an existing connector, bring a widget from one flavor to another, or implement a new shared widget end-to-end in `instantsearch.js`, `react-instantsearch`, and `vue-instantsearch`. Triggers include requests like "port X to vue", "add Y to react-instantsearch", "make Z available in all flavors", or "implement the missing InstantSearch wrapper for this connector".
/plugin install instantsearchdetails
Port InstantSearch Widgets Across Flavors
Start with the repo audit
- Run
python3 scripts/audit_widget_coverage.py <widget-kebab-name>from this skill folder before editing. - Use
--repo /path/to/instantsearchif your current working directory is not inside the InstantSearch repo. - Treat placeholder Vue failures in
packages/vue-instantsearch/src/__tests__/common-widgets.test.jsorcommon-connectors.test.jsas evidence that the connector exists but the Vue wrapper still needs work.
Layer map
- Connector:
packages/instantsearch.js/src/connectors/<widget>/connect<Pascal>.ts - JS widget:
packages/instantsearch.js/src/widgets/<widget>/<widget>.tsx - React hook:
packages/react-instantsearch-core/src/connectors/use<Pascal>.ts - React widget:
packages/react-instantsearch/src/widgets/<Pascal>.tsx - Optional React UI:
packages/react-instantsearch/src/ui/<Pascal>.tsx - Vue wrapper:
packages/vue-instantsearch/src/components/<Pascal>.vueor.js - Shared widget tests:
tests/common/widgets/<widget>/ - Shared connector tests:
tests/common/connectors/<widget>/
Variant widgets
Some widgets reuse another widget's connector with different defaults or UI. For example, menuSelect uses connectMenu/useMenu (not a dedicated connectMenuSelect). The audit will show no for connector and hook rows — this is expected. The $$widgetType still differs (ais.menuSelect vs ais.menu). When porting a variant widget, skip connector/hook creation and reuse the existing hook directly in the widget file.
Known variants: menuSelect → connectMenu/useMenu.
Workflow
- Decide the scope.
- Existing connector, missing wrapper: keep the connector API unchanged and port only the wrapper plus wrapper tests.
- Variant widget (shared connector, different UI): skip connector/hook creation; reuse the existing hook and set a distinct
$$widgetType. - Missing connector or changed render state: start in
instantsearch.js, then update every flavor and both common test suites. - Vue port for a newer recommendation, chat, or filter-suggestions feature: inspect
Hits.js,Highlighter.js,DynamicWidgets.js, andutil/vue-compat.jsbefore designing the wrapper.
- Match a real precedent.
- Pick one close widget in the target flavor and one close widget in another flavor.
- Reuse the same prop names, slot or component escape hatches,
$$widgetType, and test style.
- Build from the bottom up.
- Connector exports belong in
packages/instantsearch.js/src/connectors/index.ts. - JS widget exports belong in
packages/instantsearch.js/src/widgets/index.ts. - React hook exports belong in
packages/react-instantsearch-core/src/index.ts. - React widget exports belong in
packages/react-instantsearch/src/widgets/index.ts;packages/react-instantsearch/src/index.tsalready re-exports widgets. - Vue exports belong in
packages/vue-instantsearch/src/widgets.js;src/instantsearch.jsand the plugin re-export and register from there automatically.
- Connector exports belong in
- Choose the right sharing model.
- JS and React: prefer
instantsearch-ui-componentswhen the markup can be shared. - React: create
src/ui/<Pascal>.tsxwhenever the widget has no shared factory ininstantsearch-ui-components. This includes simple widgets likeMenuSelect(a plain<select>) —src/ui/is for all React-rendered markup, not only complex cases. - Vue: use
.vueSFCs for slot-heavy markup and.jsrender functions withrenderCompatwhen reusinginstantsearch-ui-components.
- JS and React: prefer
- Wire tests before finishing.
- Update
tests/common/widgets/<widget>/whenever the wrapper behavior changes. - Update
tests/common/connectors/<widget>/whenever connector params or render state change. - Register the suite in each flavor's
common-widgets.test.*andcommon-connectors.test.*. - Replace any
throw new Error('X is not supported in ...')placeholder with real setup code in the target flavor'scommon-widgets.test.*. - Remove the corresponding
skippedTestsentry intestOptionsfor that widget. - For React: always add the widget to the switch in
packages/react-instantsearch/src/widgets/__tests__/__utils__/all-widgets.tsxwith the required minimum props.
- Update
- Check examples only when the widget is user-facing.
- Search existing examples first. Recommendation, chat, and query-suggestion widgets already live in getting-started or query-suggestions examples, not only the e-commerce apps.
- Add to
examples/*/e-commerceonly when the widget fits the shared storefront UX or existing Playwright coverage.
Reminders
- Keep
$$widgetTypealigned across flavors. - Do not invent new Vue patterns; match
createWidgetMixin,createSuitMixin, scoped slots, andrenderCompat. - Do not add memoization hooks in React unless an adjacent widget uses them for the same reason.
Cross-package API migration checks
- Update all affected layers in one pass when moving or splitting behavior: wrapper APIs, shared UI components, layout/type contracts, exports, and tests. Wrapper-only edits create cross-package type drift.
- If you remove a required prop or render path, either delete it end-to-end or make downstream contracts optional in the same change; partial migrations often fail during declaration builds.
- Before finishing, grep for legacy names (old props, options, class names, template keys, translations keys) to catch leftovers across flavors.
- Keep control contracts explicit and consistent when behavior is externally controlled (e.g., imperative handles or widget methods), so external integrations do not depend on internal layout details.
- Do not add ad-hoc top-level markdown change logs unless requested; keep source of truth in code, tests, and existing docs.
- Always run monorepo build validation (
yarn build --ignore='example*') after cross-package API changes; it catches declaration and export drift that local tests may miss.
References
- JS wrappers: references/js-flavor.md
- React wrappers: references/react-flavor.md
- Vue wrappers: references/vue-flavor.md
- Testing and examples: references/testing.md
technical
- github
- algolia/instantsearch
- stars
- 4047
- license
- MIT
- contributors
- 100
- last commit
- 2026-05-28T21:49:29Z
- file
- .claude/skills/port-widget/SKILL.md