Imported from vtex-apps/search-result (
AGENTS.md). Install upstream withnpx skills add vtex-apps/search-result. Copyright stays with the author.
AGENTS.md — search-result
Repository Purpose
vtex.search-result is a VTEX IO Store Framework app (builders: react, messages, store, docs) that exports the PLP (Product Listing Page) blocks for VTEX storefronts: galleries, filter navigators, sort controls, layout switchers, pagination ("fetch more"/"fetch previous"), and search-context primitives.
It is the storefront consumer of the GraphQL surface published by vtex.search-graphql (resolved by vtex.search-resolver) and coordinates with vtex.delivery-promise-components for pickup-point shipping facets on PLP (shared localStorage['vtex.search.pickupInPoint'] key).
Where it sits in the IS topology
| App | Role |
|---|---|
vtex.search-graphql |
App-owned GraphQL schema |
vtex.search-resolver |
GraphQL resolvers |
vtex.intelligent-search-api |
Backend HTTP wrapper |
vtex.search-result (this repo) |
Store Framework PLP blocks |
vtex.delivery-promise-components |
Shopper-location blocks; shares pickup-in-point storage |
vtex.search-session |
Session namespace that feeds segment/facets |
Sources of Truth
| File | What it defines |
|---|---|
manifest.json |
App identity (vtex.search-result@3.145.1), builders (react, messages, store, docs), dependencies (large list — vtex.store-graphql, vtex.store-resources, vtex.store-components, vtex.product-summary, vtex.shelf, vtex.styleguide, vtex.search-page-context, vtex.pixel-manager, vtex.flex-layout, vtex.tab-layout, vtex.breadcrumb, vtex.native-types, vtex.responsive-values, vtex.format-currency, vtex.css-handles, …), registries: [smartcheckout], scripts.postreleasy: vtex publish --verbose |
store/interfaces.json |
The block contract. All blocks exported by this app (search-result, gallery, filter-navigator v1/v2/legacy, gallery-layout-switcher, gallery-layout-option, not-found, order-by, total-products, search-title, search-result-layout + variants, search-content, search-fetch-more, search-fetch-previous, search-layout-switcher, …). Each entry maps a block name → React component + allowed/required/composition/content rules. |
store/blocks.json |
Default block tree compositions (e.g. search-result defaults to [filter-navigator, gallery, not-found, breadcrumb, total-products, order-by]). |
store/contentSchemas.json |
JSON Schemas for Site Editor prop configuration of the blocks. |
react/index.js |
The SearchResult block entry — wires LocalQuery, SORT_OPTIONS, LAYOUT_MODE, PAGINATION_TYPES, and ContextProviders. |
react/Gallery.tsx, react/GalleryLegacy.tsx, react/GalleryLayout.tsx, react/GalleryLayoutSwitcher.tsx, react/GalleryLayoutOption.tsx |
Gallery family — main product grid. |
react/FilterNavigator.js, react/FilterNavigatorLegacy.js, react/FilterNavigatorFlexible.js, react/FilterNavigatorContext.js |
Filter Navigator family (3 implementations coexist for migration). |
react/OrderBy.js, react/OrderByFlexible.js, react/TotalProducts.js, react/TotalProductsFlexible.js, react/SearchTitle.js, react/SearchTitleFlexible.js, react/NotFoundSearch.js, react/NotFoundLayout.js |
Smaller PLP blocks. |
react/SearchResultLayout.js, react/SearchResultLayoutCustomQuery.js, react/SearchResultFlexible.js, react/SearchResultFlexibleMobile.js, react/SearchContent.js, react/SearchQuery.js |
Layout containers and query loaders. |
react/FetchMore.js, react/FetchPrevious.js, react/ProductCountPerPage.js, react/ProductsProgressBar.js, react/LayoutModeSwitcher.js, react/LayoutModeSwitcherFlexible.js, react/SidebarCloseButton.js |
Pagination and layout controls. |
react/constants.ts, react/constants/ |
SORT_OPTIONS, LAYOUT_MODE, pagination type enums. |
react/hooks/ |
Reusable hooks (e.g. facet navigation). |
react/queries/ |
Apollo GraphQL queries used by LocalQuery and other loaders. |
react/components/ |
Shared sub-components used across blocks (SearchResultContainer, LocalQuery, ContextProviders, etc.). |
react/utils/ |
Pure utilities (URL parsing, facet normalization). |
react/__tests__/ |
Test suites (FilterNavigator.test.js, Gallery.test.js, OrderBy.test.js, SearchFooter.test.js, AccordionFilterContainer.test.js, useFacetNavigation.test.js, etc.). |
react/__mocks__/ |
Manual jest mocks. |
react/tsconfig.json, react/typings/ |
Platform typings — regenerated by Toolbelt; do not hand-edit typings/ |
react/searchResult.css |
Top-level CSS for the suite. |
messages/ |
i18n catalogs (crowdin-managed via crowdin.yml). |
.vtex/deployment.yaml, .vtex/catalog-info.yaml |
DK CI deployment + Backstage entity (referenceId: UWERS1CF). |
CHANGELOG.md |
Per-release changelog. |
Architecture
Storefront route renders <search-result>
│
├─► SearchResultContainer
│ ├─ LocalQuery (when no parent layout provides data)
│ │ └─ Apollo query against vtex.store-graphql / vtex.search-graphql
│ └─ SearchPageContext provider (from vtex.search-page-context)
│
└─► child blocks composed in store/blocks.json
├─ <filter-navigator> → FilterNavigatorLegacy | FilterNavigator | FilterNavigatorFlexible
├─ <gallery> → Gallery | GalleryLegacy → uses <product-summary> (vtex.product-summary)
├─ <gallery-layout-switcher> → GalleryLayoutSwitcher (composition: children)
├─ <gallery-layout-option> → GalleryLayoutOption (composition: children)
├─ <order-by> → OrderBy | OrderByFlexible
├─ <total-products> → TotalProducts | TotalProductsFlexible
├─ <search-title> → SearchTitle | SearchTitleFlexible
├─ <not-found> → NotFoundSearch (allowed: shelf)
├─ <search-fetch-more> → FetchMore
├─ <search-fetch-previous> → FetchPrevious
└─ <search-products-progress-bar> → ProductsProgressBar
FilterNavigator family
Three implementations coexist for migration:
| Block | Component | Used by |
|---|---|---|
filter-navigator (unversioned alias) |
FilterNavigatorLegacy |
Legacy stores |
filter-navigator.v1 |
FilterNavigatorLegacy |
Explicit legacy |
filter-navigator.v2 |
FilterNavigator |
New stores (allows shop-review-summary, sidebar-close-button) |
(flexible variant via search-layout-switcher / flex-layout) |
FilterNavigatorFlexible |
Stores using vtex.flex-layout |
The v2 component is the active development target. Legacy variants are maintained for backwards compatibility — do not refactor them without explicit cross-team coordination.
Shared state with vtex.delivery-promise-components
This app reads localStorage['vtex.search.pickupInPoint'] to scope PLP filtering by the shopper's selected pickup point. The key is owned by vtex.delivery-promise-components (see its react/pickupInPointPreference.ts). Format:
{ id: string, friendlyName: string, address: string, postalCode: string }
vtex.delivery-promise-components invalidates this when the stored postalCode differs from the current session.
Verified Commands
make dev # yarn install (root + react) + vtex setup
make lint # eslint (no --fix)
make test # cd react && yarn test (vtex-test-tools)
make coverage # cd react && yarn test --coverage (60% threshold via react/package.json jest key)
make check # lint + test (pre-PR gate)
make link # vtex link (uses active VTEX account/workspace)
make run # alias for make link
Root yarn scripts: yarn lint, yarn format, yarn test.
CI
.github/workflows/pull-request.yml triggers on PRs targeting master. It runs three jobs:
danger-ci—vtex/dangerenforces changelog and PR conventions.io-app-test—vtex/action-io-app-testrunsvtex-test-toolsin thereactbuilder.lint—vtex/action-lintruns the linter.
Node 12 is still the CI target. The dependency tree (TypeScript 3.7,
@types/node 13, jsdom 16, jest-environment-jsdom 26) is locked to that era. A future runtime bump should be a dedicated PR — golden-path keeps Node 12 here on purpose.
Expected Skills
vtex-io-cli·vtex-io-app-structure·vtex-io-react-apps·vtex-store-framework-navigatorspecification+implementing(vtex-agent-skills) for SDD Lite- For SDD Full work, use the spec-kit pipeline against the parent Specs repo
Expected MCPs
- GitHub MCP — cross-repo references (especially
vtex.search-graphql,vtex.search-resolver,vtex.delivery-promise-components,vtex.product-summary). - Atlassian MCP — Jira/Confluence context.
- Consider Playwright /
vtex-qafor E2E generation against PLP blocks.
Multi-repo Specs
Part of the is-io-specs multi-repo workspace. SpecKit artifacts live at the parent aggregator (is-io-specs/.specify/, is-io-specs/specs/). This repo intentionally has no local .specify/. See the Multi-repo spec-kit extension.
Autonomy Limits
Toolbelt and platform
- Never run
vtex link,vtex publish,vtex deploy, workspace promotion, or any account/workspace-changing Toolbelt command without explicit confirmation. - Ask before running
vtex setup --tooling— this repo useseslint-config-vtex@^12+eslint-config-vtex-react@^6with custom rules in.eslintrc;vtex setup --toolingcould overwrite them. - Never modify
manifest.jsonversiondirectly — usevtex release <patch|minor|major> stable. - Never modify
react/typings/— regenerated byvtex setup --typings --ignore-linked. - Note:
manifest.json:scripts.postreleasy: "vtex publish --verbose"means a successfulvtex releaseautomatically publishes. This is part of the team's release flow but worth flagging in any release-related PR.
Block contract
- Never remove a block name from
store/interfaces.jsonwithout a coordinated deprecation cycle — themes in production rely on block names being stable. - Adding allowed children to an existing block is safe.
- Removing
requiredchildren is breaking — themes may stop rendering correctly. - The
filter-navigator(unversioned) alias still resolves toFilterNavigatorLegacy. Changing that mapping is a stealth breaking change for any theme that uses the unversioned name. Always change.v1/.v2explicitly.
React component constraints
- Three FilterNavigator implementations coexist by design —
FilterNavigator(v2, active),FilterNavigatorLegacy(compat),FilterNavigatorFlexible(flex-layout). Do not collapse them without explicit cross-team coordination. - The repo mixes
.js,.ts,.tsx. New files should be.tsx(with proper TypeScript types). Avoid migrating legacy.jsfiles in passing — keep the migration deliberate. - CSS handles are exposed via
vtex.css-handles. Adding handles is safe; renaming or removing them is a breaking theme change.
Storage and analytics
localStorage['vtex.search.pickupInPoint']is owned byvtex.delivery-promise-components, not this repo. Read it; do not write it.- Pixel events are emitted via
vtex.pixel-manager. Adding new events is safe; renaming or removing existing ones breaks analytics dashboards.
Branch / release flow
- Current default branch is
master(not yet migrated tomain). PR workflow triggers onmaster. Confirm before any branch rename. vtex release patch stable(orminor/major) creates the tag;postreleasythen publishes.
Test maintenance
- New tests go in
react/__tests__/usingvtex-test-tools. Coverage threshold (60%) is declared under thejestkey inreact/package.json. - The legacy mocks live in
react/__mocks__/. Preferjest.mock()at the test level for new fixtures.