Marketplace Home Page React block for Tailwind CSS v4
v1.0.1Updated in 1.9.0
A React marketplace home page with a what and where search, category tiles, a promoted rail, new listings near you and an app band.
Type what you look for in the hero search, pick the place in the location field (it filters the towns of lib/ro-locations, accents optional, and offers All locations) and press Enter or Search: onSearch gets the text and the city id, by default the page navigates to /search?q=…&loc=…. Below 768px the two fields and the button stack and the location opens a full height sheet. The popular searches under it are links (a sideways scroll on phones). The category tiles are links to /search?cat=…; arrow keys move between them, phones show the first nine and All categories below. Promoted listings is a swipeable rail (1.3 cards on a phone, 4 on a laptop) with arrow buttons in its header on fine pointers and arrow keys when it has focus; the Promoted badge opens an explanation (a popover, a bottom sheet on phones). New listings in Cluj-Napoca: the city chip opens a searchable list of places (a sheet on phones) and the grid shows the newest listings there; a city with nothing yet shows No listings in Sibiu yet with Search every location. Hearts save a listing at once, in the rail and in the grid together; a rejected onFavoriteChange rolls the heart back. See all listings opens the results. The trust tiles and the app band (bullets, App Store and Google Play buttons, a QR code to scan on desktop) close the page. Sections rise in once when the page mounts on the client; reduced motion skips it.
Marketplace Home Page is a Pro React block in the React blocks category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add marketplace-home-page, together with Badge, Button, Carousel, Category picker, Combobox and 19 more and the npm packages motion and lucide-react.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add marketplace-home-pageMarketplace Home Page is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import MarketplaceHomePage from @/components/blocks/marketplace-home-page.
// app/(market)/page.tsx (the shell lives in app/(market)/layout.tsx)
"use client"
import { useRouter } from "next/navigation"
import { MarketplaceHomePage } from "@/components/blocks/marketplace-home-page"
export default function HomePage() {
const router = useRouter()
return (
<MarketplaceHomePage
defaultLocation="cluj-napoca"
onSearch={({ query, location }) => router.push(`/search?q=${encodeURIComponent(query)}&loc=${location}`)}
onFavoriteChange={(id, favorite) => fetch(`/api/favorites/${id}`, { method: favorite ? "PUT" : "DELETE" })}
/>
)
}Props
categoriesMarketplaceHomeCategory[]The category tiles (MARKETPLACE_HOME_SAMPLE.categories: the 12 Northwind Market categories with lucide icons and counts). Each links to /search?cat=<id> unless it has its own href.
promotedListingData[]The promoted rail (MARKETPLACE_HOME_SAMPLE.promoted: l02, l04 and six generated promoted ads). Empty hides the section.
recentListingData[]The newest listings, newest first (MARKETPLACE_HOME_SAMPLE.recent: l01 to l08 plus 16 generated, mostly in Cluj-Napoca). The grid keeps the listings whose location starts with the chosen city.
popularSearchesstring[]The quick searches under the hero search (MARKETPLACE_HOME_SAMPLE.popularSearches: iPhone 14, Bike, 2-bedroom apartment...).
stats{ listings: number; sellers: number; cities: number }The hero subline (MARKETPLACE_HOME_SAMPLE.stats: 1,284,310 listings in 3,180 towns and villages), through labels.stats.
locationstringThe chosen city, a ro-locations id; controlled with onLocationChange. "" is every location, an unknown id reads as All locations.
defaultLocationdefault"cluj-napoca"stringThe starting city of the recent section and the hero search while uncontrolled.
onLocationChange(location: string) => voidEvery city change, from the hero field, the chip or the empty state.
onSearch(query: { query: string; location: string; category: string }) => voidThe hero search. Default: navigates to /search?q=…&loc=… through the link provider's navigate.
heroVariantdefault"panel""panel" | "plain"panel: a tinted rounded hero with a photo mosaic from 768px (flat on phones); plain: the hero sits on the page background.
showPromoteddefaulttruebooleanThe promoted rail.
showRecentdefaulttruebooleanThe new ads grid with the city chip.
showTrustdefaulttruebooleanThe three trust tiles.
showAppdefaulttruebooleanThe app band with the store buttons and the QR code.
recentCountdefault12numberAds in the recent grid (fewer when the city has fewer).
cardSizedefault"md""sm" | "md"Listing card size from 640px; phones always use the compact look in two columns.
onFavoriteChange(id: string, favorite: boolean) => (void | Promise<unknown>)A heart was toggled. The change shows at once in the rail and the grid; a rejected promise rolls it back and the card announces the error.
appUrldefault"https://northwind.market/app"stringThe QR code's value in the app band.
appStoreHrefdefault"#app-store"stringThe App Store button's link.
googlePlayHrefdefault"#google-play"stringThe Google Play button's link.
categoriesHrefdefault"/categories"stringWhere All categories points.
deliveryFromdefault9.99numberThe lowest courier price in the Courier delivery tile, in currency.
labelsPartial<MarketplaceHomePageLabels>Every visible string (DEFAULT_MARKETPLACE_HOME_PAGE_LABELS, English), counted ones as functions; nested listingCard, carousel, categoryPicker, searchInput, listbox and qrCode labels for the composed items. MARKETPLACE_HOME_PAGE_LABELS_EN is the same set under its older name.
localedefault"en-US"stringIntl locale for the counts, prices and dates.
currencydefault"USD"stringThe currency of listings without their own, and of deliveryFrom.
nowDate | numberThe clock for the relative dates on the cards. Default: useNow() (a stable placeholder while hydrating); the demo passes MARKETPLACE_HOME_NOW.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"The search button, the hero glow, the selected place, the hearts and the trust icons.
radiusdefault"md""sm" | "md" | "lg"The surfaces: cards and tiles 12 / 16 / 24px, the hero and the app band 16 / 24 / 32px.
loadingdefaultfalsebooleanThe hero stays; the category tiles, the promoted rail and the grid become skeletons of their real shape.
animateIndefaulttruebooleanSections rise in once when the page mounts on the client (never over server HTML, never with reduced motion).
linkComponent(props: LinkComponentProps) => ReactNodeThe router link for every link on the page. Default: the provider's (the shell's), then <a>.
classNamestringClasses for the root.
classNamesPartial<Record<"hero" | "search" | "categories" | "promoted" | "recent" | "grid" | "trust" | "app", string>>Classes for the sections.
Parts
DEFAULT_MARKETPLACE_HOME_PAGE_LABELS
constantThe English strings for every visible label, the default of labels. Type: MarketplaceHomePageLabels.
MARKETPLACE_HOME_PAGE_LABELS_EN
constantThe same English strings under their older name, kept for existing imports.
MARKETPLACE_HOME_SAMPLE
constantThe demo data in USD: 12 categories, 8 promoted and 24 recent listings, popular searches and the hero stats.
MARKETPLACE_HOME_SAMPLE_EN
constantThe same sample priced in EUR, converted at USD_PER_EUR (the currency example).
createMarketplaceHomeSample
functionBuilds the sample: ({ currency?: "USD" | "EUR" }) => MarketplaceHomeSample, with seeded generated listings.
MARKETPLACE_HOME_NOW
constantThe demo clock (Sep 24, 2026, 4:40 PM) as a timestamp, passed as now so relative dates stay stable.
USD_PER_EUR
constantThe rounded dollars per euro rate (1.09) used to convert the EUR sample.
mulberry32
functionA tiny seeded random generator, (seed: number) => () => number, so the generated sample listings stay the same on every render.
MarketplaceHomePageProps
typeProps of MarketplaceHomePage, including the div attributes of the root.
MarketplaceHomeCategory
typeA category tile: id, label, icon, listing count, search keywords and an optional href.
MarketplaceHomeSearchQuery
typeWhat onSearch receives: { query: string; location: string; category: string }.
Examples
Plain hero, brand actions
The hero sits on the page background; the shell's Post a listing and the search button use the brand tone.
Loading
Category tiles, the promoted rail and the grid as skeletons of their real shape.
A city with no listings yet
Sibiu has nothing new: the empty state offers every location.
Euro prices
en-GB formatting and the same listings priced in euro.
Compact, every location
Small cards, 8 listings from every location, large radius, info tone and no trust tiles.
Dependencies
Files
- components/blocks/marketplace-home-page.tsx
- components/blocks/marketplace-home-page-data.ts
FAQ
Is the React Marketplace Home Page block free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Marketplace Home Page?
Run npx wingo-ui@latest add marketplace-home-page. It also adds the Wingo UI items it builds on (Badge, Button, Carousel, Category picker, Combobox and 19 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/marketplace-home-page.
How does Marketplace Home Page behave on phones?
Below 768px the two fields and the button stack and the location opens a full height sheet. The popular searches under it are links (a sideways scroll on phones).
See also
More React blocks
Articles using this component
- Shadcn Ecommerce Template: Five Screens That Work on Phones
Build it: screens and apps11 min read
- React Marketplace Template That Works Like an App
Build it: screens and apps15 min read