# Marketplace Shell

> A React marketplace layout shell with a what and where search header, a category strip, a footer, bottom tabs on phones and cookie consent.

- Type: React block (Blocks)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add marketplace-shell`
- Docs: https://wingo-ui.com/components/marketplace-shell

## Interaction

On desktop the header holds the logo, one joined search box and the actions. Type in the query field (press / to focus it): while it is empty it lists your recent searches (remove one with its x or Delete, or clear them) and the popular ones; while typing it suggests categories (Mobile phones, in Electronics › Phones) and matching listings; arrows and Enter pick one. The location field filters the Romanian cities without diacritics and offers All locations and Near me (your position when the browser allows it, else your own city). Enter or Search submits the query, the place and the category; a category chip in the box scopes the search and its x removes it. Favorites and messages carry counts, the avatar opens the account menu (my account, listings, favorites, messages, settings, the theme and sign out), and Post a listing starts a new listing. The category strip below scrolls sideways with edge fades and marks the active category. Once the page scrolls the header gains a hairline and a soft shadow. Below 768px the header is a compact row: the logo mark, a search field that opens a full height sheet (autofocused input, the location as a row that opens its own sheet, recent searches with remove buttons, popular searches and category tiles; Escape, the handle or Cancel closes it) and the avatar. A bottom tab bar holds Home, Search (opens the sheet), the raised Post action, Messages with its count and Account. The minimal variant keeps only the logo, a back or close button and a trust note. The cookie banner shows until the visitor decides and sits above the tab bar; Cookie settings in the footer reopens its settings. The skip link (Skip to content) is the first stop for keyboard users.

## Installation

```bash
npx wingo-ui@latest add marketplace-shell
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/marketplace-shell` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `components/blocks/marketplace-shell.tsx`
- `components/blocks/marketplace-shell-data.ts`

npm dependencies: `npm i lucide-react`

Wingo UI dependencies (installed automatically):

- [Badge](https://wingo-ui.com/components/badge) ([Markdown](https://wingo-ui.com/components/badge.md))
- [Bottom Tab Bar](https://wingo-ui.com/components/bottom-tab-bar) ([Markdown](https://wingo-ui.com/components/bottom-tab-bar.md))
- [Button](https://wingo-ui.com/components/button) ([Markdown](https://wingo-ui.com/components/button.md))
- [Combobox](https://wingo-ui.com/components/combobox) ([Markdown](https://wingo-ui.com/components/combobox.md))
- [Cookie Consent](https://wingo-ui.com/components/cookie-consent) ([Markdown](https://wingo-ui.com/components/cookie-consent.md))
- [Drawer](https://wingo-ui.com/components/drawer) ([Markdown](https://wingo-ui.com/components/drawer.md))
- [Search Input](https://wingo-ui.com/components/search-input) ([Markdown](https://wingo-ui.com/components/search-input.md))
- [Separator](https://wingo-ui.com/components/separator) ([Markdown](https://wingo-ui.com/components/separator.md))
- [Theme Toggle](https://wingo-ui.com/components/theme-toggle) ([Markdown](https://wingo-ui.com/components/theme-toggle.md))
- [Toast](https://wingo-ui.com/components/toast) ([Markdown](https://wingo-ui.com/components/toast.md))
- [User Menu](https://wingo-ui.com/components/user-menu) ([Markdown](https://wingo-ui.com/components/user-menu.md))
- [useMediaQuery](https://wingo-ui.com/components/use-media-query) ([Markdown](https://wingo-ui.com/components/use-media-query.md))
- [useScrollState](https://wingo-ui.com/components/use-scroll-state) ([Markdown](https://wingo-ui.com/components/use-scroll-state.md))
- [useShortcut](https://wingo-ui.com/components/use-shortcut) ([Markdown](https://wingo-ui.com/components/use-shortcut.md))
- [Navigation](https://wingo-ui.com/components/navigation) ([Markdown](https://wingo-ui.com/components/navigation.md))
- [Number format](https://wingo-ui.com/components/number-format) ([Markdown](https://wingo-ui.com/components/number-format.md))
- [Romanian locations](https://wingo-ui.com/components/ro-locations) ([Markdown](https://wingo-ui.com/components/ro-locations.md))
- [Text match](https://wingo-ui.com/components/text-match) ([Markdown](https://wingo-ui.com/components/text-match.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))
- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
// app/(market)/layout.tsx
"use client"

import Link from "next/link"
import { usePathname, useRouter } from "next/navigation"
import type { ReactNode } from "react"
import { MarketplaceShell } from "@/components/blocks/marketplace-shell"

export default function MarketLayout({ children }: { children: ReactNode }) {
  const pathname = usePathname()
  const router = useRouter()
  return (
    <MarketplaceShell currentPath={pathname} linkComponent={Link} onNavigate={router.push}>
      {children}
    </MarketplaceShell>
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children?` | `ReactNode` |  | The page, rendered once inside main. |
| `variant?` | `"full" \| "minimal"` | `"full"` | minimal: logo, minimalAction and minimalNote only (checkout, the publishing wizard); no search, categories, footer or tabs. |
| `layout?` | `"page" \| "fill"` | `"page"` | page: the window scrolls under a sticky header and the footer follows the content. fill: the shell is exactly the viewport, main is a flex column for inboxes, the footer is hidden and the tab bar sits in the flow. |
| `currentPath?` | `string` | `"/"` | The active route (next: usePathname()). Selects the tab and the category chip; nested routes match by prefix. |
| `categories?` | `MarketplaceCategory[]` |  | The category tree (MARKETPLACE_SHELL_SAMPLE.categories: the 12 Northwind Market categories with lucide icons, counts and subtrees for Vehicles, Real estate and Electronics). The strip shows the top level; the search suggests any level. Compatible with category-picker's CategoryNode. |
| `user?` | `{ name: string; email?: string; avatar?: string; city?: string } \| null` |  | The signed-in buyer (MARKETPLACE_SHELL_SAMPLE.user: Emma Carter, city cluj-napoca). null shows Sign in (loginHref). city is the fallback of Near me. |
| `userMenuItems?` | `UserMenuEntry[]` |  | The account menu entries above sign out. Default: My account, My listings, Favorites, Messages, Settings and a separator. |
| `onSignOut?` | `() => (void \| Promise<unknown>)` |  | The sign-out row. Default: a toast "Te-ai deconectat". |
| `favoritesCount?` | `number` | `4` | The favorites badge (99+ above 99). 0 hides the badge, the icon stays. |
| `messagesCount?` | `number` | `2` | Unread messages on the header icon and the Mesaje tab. 0 hides the badges. |
| `favoritesHref?` | `string` | `"/favorites"` | Where the heart points. |
| `messagesHref?` | `string` | `"/messages"` | Where the messages icon and tab point. |
| `searchPlaceholder?` | `string` | `"Search 1,284,310 listings"` | The query field's and the phone field's placeholder. Empty uses labels.searchPlaceholder. |
| `defaultQuery?` | `string` | `""` | The query the search starts with. |
| `defaultLocation?` | `string` | `""` | A ro-locations city id the search starts with ("cluj-napoca"); "" is All locations. An unknown id shows as typed. |
| `defaultCategory?` | `string` | `""` | A category id that scopes the search ("phones"); shown as a removable chip in the box. |
| `onSearch?` | `(query: { query: string; location: string; category: string }) => void` |  | Runs on Enter, Search, a suggestion or a recent search. Default: navigates to /cautare?q=…&loc=…&cat=… through the router. |
| `popularSearches?` | `string[]` |  | Suggested while the field is empty (MARKETPLACE_SHELL_SAMPLE.popularSearches: iPhone 14, Bike, 2-bedroom apartment, Sofa, Honda Civic). |
| `recentSearches?` | `string[]` |  | The recent searches the field starts with (city bike, macbook air); each submit adds one, and each can be removed. |
| `locations?` | `LocationOption[]` |  | The location combobox's cities. Default: cityOptions() from ro-locations, largest first; All locations and Near me are always on top. |
| `searchShortcut?` | `string` | `"/"` | Focuses the search on desktop and opens the search sheet on phones. "" binds nothing. |
| `postHref?` | `string` | `"/post"` | Where Post a listing and the tab bar's raised action point. |
| `onPost?` | `() => void` |  | Replaces the postHref link with a button (open a dialog, check sign-in first). |
| `minimalAction?` | `"back" \| "close" \| "none"` | `"back"` | The minimal variant's leading button. |
| `minimalNote?` | `ReactNode` |  | The minimal variant's trailing trust note. Default: a lock and Secure payment. |
| `onBack?` | `() => void` |  | The minimal button. Default: history.back() when there is history, else backHref. |
| `backHref?` | `string` | `"/"` | Where the minimal button goes without history. |
| `showCategories?` | `boolean` | `true` | The category strip under the header (768px and up). |
| `footer?` | `boolean` | `true` | The footer with the link columns, the app badges, the cookie settings and the theme (page layout, full variant). |
| `footerLinks?` | `{ title: string; links: { label: string; href: string }[] }[]` |  | The footer columns (MARKETPLACE_SHELL_SAMPLE.footerLinks: Northwind Market, Help, Legal, For business). |
| `footerNote?` | `ReactNode` |  | Extra content in the footer's bottom row, next to Cookie settings. |
| `appBadges?` | `boolean` | `true` | App Store and Google Play buttons in the footer (neutral buttons with an icon and text, no brand artwork). |
| `tabBar?` | `boolean` | `true` | The phone tab bar: Home, Search, the raised Post, Messages and Account. |
| `hideTabBar?` | `boolean` | `false` | Hides the tab bar for a while (a page with its own sticky bar, thumbnails). |
| `cookieConsent?` | `boolean` | `true` | Renders CookieConsent until the visitor decides; it sits above the tab bar. |
| `consentStorageKey?` | `string` | `"northwind-market-consent"` | The consent cookie's name (the demo appends -demo so it never touches a real choice). |
| `consentCategories?` | `ConsentCategoryConfig[]` |  | The consent categories. Default: DEFAULT_CONSENT_CATEGORY_CONFIG. |
| `ctaTone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` | The fill of Post a listing, Search, the tab bar's raised action and the consent's accept button. |
| `loginHref?` | `string` | `"/login"` | Where Sign in points while signed out. |
| `accountHref?` | `string` | `"/account"` | The Cont tab and the account menu's base path. |
| `logo?` | `ReactNode` |  | Replaces the default mark and Northwind Market wordmark. |
| `locale?` | `string` | `"en-US"` | Intl locale for the counts. |
| `tone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` | The active category chip and the active tab. |
| `linkComponent?` | `(props: LinkComponentProps) => ReactNode` |  | The router link every link renders through (next/link). Default: the LinkProvider's, else <a>. |
| `onNavigate?` | `(href: string) => void` |  | The router's push for the default search and the account menu (next: useRouter().push). |
| `labels?` | `Partial<MarketplaceShellLabels>` |  | Every visible string. English by default (DEFAULT_MARKETPLACE_SHELL_LABELS; MARKETPLACE_SHELL_LABELS_EN is the same set under its older name). |
| `classNames?` | `Partial<Record<"header" \| "search" \| "categories" \| "main" \| "footer" \| "tabs", string>>` |  | Extra classes for the inner parts. |
| `className?` | `string` |  | Extra classes for the root. Other props spread onto it. |

## Parts

### DEFAULT_MARKETPLACE_SHELL_LABELS (constant)

The English strings for every visible label, the default of labels. Type: MarketplaceShellLabels.

### MARKETPLACE_SHELL_LABELS_EN (constant)

The same English strings under their older name, kept for existing imports.

### MARKETPLACE_SHELL_SAMPLE (constant)

The Northwind Market demo data: categories, footer links, popular and recent searches, listing titles, the listing count and the user.

### MarketplaceShellProps (type)

Props of MarketplaceShell, including the div attributes of the root.

### MarketplaceCategory (type)

A category in the strip and the search: id, label, icon and optional children.

### MarketplaceSearchQuery (type)

What the header search submits: the text, the location and the category.

## Examples

- **Signed out**: user={null}: Sign in in the header and the tab bar; zero counts hide the badges.
- **Minimal checkout frame**: variant="minimal": logo, a back button and a trust note; no search, categories, footer or tabs.
- **Brand CTA with a scoped search**: ctaTone="brand" and tone="brand"; the search starts in Phones, Cluj-Napoca.
- **Fill layout with an inbox**: layout="fill": the shell is the viewport, no footer, the panes scroll inside.

## See also

- [Admin Shell](https://wingo-ui.com/components/admin-shell) ([Markdown](https://wingo-ui.com/components/admin-shell.md))
- [Marketplace Home Page](https://wingo-ui.com/components/marketplace-home-page) ([Markdown](https://wingo-ui.com/components/marketplace-home-page.md))
- [Bottom Tab Bar](https://wingo-ui.com/components/bottom-tab-bar) ([Markdown](https://wingo-ui.com/components/bottom-tab-bar.md))
- [Search Input](https://wingo-ui.com/components/search-input) ([Markdown](https://wingo-ui.com/components/search-input.md))
- [Cookie Consent](https://wingo-ui.com/components/cookie-consent) ([Markdown](https://wingo-ui.com/components/cookie-consent.md))
- [Listing grid](https://wingo-ui.com/components/listing-grid) ([Markdown](https://wingo-ui.com/components/listing-grid.md))

---

Canonical: https://wingo-ui.com/components/marketplace-shell
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
