Libraries
A Studio library of the tenant as a card section (like the websites library sections): areas, condo buildings, new developments, saved searches, collections, blog stories, team members or client reviews (the quote and…
Anatomy
Every piece of Libraries as it nests in code. A root holds the data and state; its parts and hooks only work inside it.
<PandaProvider>Mounted once in app/layout.tsx<PandaLibrary />complete widgetA Studio library of the tenant as a card section (like the websites library sections): areas, condo buildings, new developments, saved…
</PandaProvider>Installation
- 1npm install <tarball or @pandaidx/widgets>Terminalnpm install https://github.com/pandaidx/panda-widgets/releases/download/v1.14.1/pandaidx-widgets-1.14.1.tgz
- 2import "@pandaidx/widgets/styles.css" in app/layout.tsx
- 3Wrap the site in <PandaProvider publicKey apiUrl preset theme> (app/layout.tsx)
- 4In each page (Server Component) call the widget's server loader, then render the widget with its data
- 5Allow the images: next.config images.remotePatterns [{ protocol: "https", hostname: "**" }] (listing and blog photos come from several CDNs)
Usage
// app/page.tsx: the homepage buildings library as a carouselimport { PandaLibrary } from "@pandaidx/widgets/client"import { fetchLibraries, fetchLibrary } from "@pandaidx/widgets/server"const config = { publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL }export default async function Home() {const { libraries } = await fetchLibraries(config)const buildings = libraries.find((library) => library.type === "buildings")const data = buildings ? await fetchLibrary({ ...config, libraryId: buildings.id, limit: 12 }) : null// Bind only routes actually rendering these widgets; each section may choose another instance.return <PandaLibrary data={data} layout="carousel" columns={3} linkRoutes={{ propertySearch: "/properties", buildingDetail: "/condos/{slug}" }} />}
API reference
PandaLibrary
A Studio library of the tenant as a card section (like the websites library sections): areas, condo buildings, new developments, saved searches, collections, blog stories, team members or client reviews (the quote and the reviewer, no cover photo), in a grid, carousel or list. Each item links to a host route built from hrefBuilder.
Import from @pandaidx/widgets/client · renders inside PandaProvider
| Prop | Type | Default | Description |
|---|---|---|---|
| data | object | — | Library + items from the server loader (null → renders nothing). Omit it to load libraryId in the browser. |
| libraryId | string | — | Library to load in the browser when data is omitted (ids from fetchLibraries()). |
| layout | "grid" | "carousel" | "list" | "grid" | Columns grid, swipe carousel with arrows, or one wide card per row. |
| columns | object | 3 | Grid (or cards per carousel view) columns: a number 1-4 (desktop; phones 1, tablets up to 2) or { base, sm, md, lg, xl } per breakpoint. |
| cardVariant | "classic" | "overlay" | "minimal" | "horizontal" | "classic" | Card design: photo on top, text over the photo, frameless, or photo beside the text (default in list). |
| limit | number | — | Max cards shown (the loader resolves 16 by default, 48 max). |
| showTitle | boolean | true | Shows the library name as the heading. |
| title | string | — | Heading instead of the library name. |
| subtitle | string | — | Copy under the heading. |
| ctaLabel | string | — | Card button text for every item (empty string hides it). Default per type: View Area, View Building, View Project, View Listings, View Collection, Read Story, View Profile, Read Reviews. |
| hrefBuilder | object | {"areas":"{href}","buildings":"{href}","newDevelopments":"{href}","savedSearches":"{href}","collections":"{href}","stories":"{href}","team":"{href}","reviews":"{href}"} | Host route template per item type; placeholders {href} (the item's ready-made link with filters encoded, Panda paths), {slug}, {id}, {query} (saved search query) and {path} (Panda path). {forSale}, {forRent}, {pending} and {sold} select the corresponding API item.links URL verbatim (areas, buildings, new developments); missing URL = no link, never construct it from a title or slug. Empty string = no link. Default: every type opens {href} (area → /search?q=<AREA>…, building → /condos/<slug>, new development → /new-development/<slug>, saved search → /search?<query>, collection → /collection/<slug>, story → /story/<slug>, member → /team/<slug>, review → /profile#reviews). |
| areaLink | "forSale" | "forRent" | "pending" | "sold" | "condos" | "newDevelopments" | "forSale" | Where area cards link (item.links): the area's property search for sale / for rent / pending / sold, or its condo (/condos?area=<slug>) / new developments (/new-developments?city=<Name>) directory. |
| showCounts | boolean | true | Shows live for-sale / for-rent counters and listing counts. |
| emptyMessage | string | "" | Copy when the library is empty (empty = render nothing). |
| classNames | object | — | Host classes appended to any slot (see slots). |
| preset | "default" | "template1" | — | Preset for this widget only (defaults to the provider preset). |
| variant | "default" | "template1" | — | Deprecated alias of preset. |
| theme | object | — | Token overrides for this widget only, merged over the provider theme (same shape as PandaProvider.theme). |
| linkRoutes | object | — | Actual widget mounts, independently chosen per section: propertySearch, condoDirectory, newDevelopments, buildingDetail, newDevelopmentDetail, collection, story, team, profile. Detail routes require {slug}. Example: { propertySearch: '/pepito', condoDirectory: '/buildings', buildingDetail: '/buildings/{slug}' }. Uses the API links and preserves their complete query; missing route/data disables the link. See navigation.libraries. |
| destinations | object | — | API action per item type (default, detail, propertySearch, forSale, forRent, pending, sold, condos, newDevelopments); allowed actions are listed in navigation.libraries. Example: { buildings: 'forRent', areas: 'condos' }. Requires linkRoutes; no invented fallback. |
Server data
Loaders run in a Server Component and come from @pandaidx/widgets/server. Typed data is for a page you design yourself, rendered inside the root.
fetchLibrary()widget loaderOne library with its items as uniform cards (GET /v1/libraries/:id: href with filters encoded, counters, weekly trends, price ranges, images; stories add their categories slugs, reviews their quote text); null when the id is neither the tenant's nor a Panda template. List them with fetchLibraries() (GET /v1/libraries: id, name, type, source tenant|template, item count, preview images, placement). The widget is optional: any section can render the same data its own way. Returns SiteLibraryResponse | null → data