MLS Sheet
The printable MLS sheet of a listing (Panda /mls/<id>/sheet, linked by the panda listing detail): Back to Listing / Print toolbar, photo + price + address header, General, Location, Rooms, Financial, Additional and…
Anatomy
Every piece of MLS Sheet as it nests in code. A root holds the data and state; its parts and hooks only work inside it. MlsSheetCompliance must render in every layout (MLS and consent rules).
<PandaProvider>Mounted once in app/layout.tsx<MlsSheet />complete widgetThe printable MLS sheet of a listing (Panda /mls/<id>/sheet, linked by the panda listing detail): Back to Listing / Print toolbar, photo +…
<MlsSheetRoot>Holds the data and state its parts and hooks read<MlsSheetCompliance />requiredRequired: the Listing by <office> courtesy line, the feed's disclaimer and the accuracy / consumer-use notices.
<MlsSheetPrint />Print button (window.print()), hidden when printing.
</MlsSheetRoot></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/(print)/mls/[listingId]/sheet/page.tsx (no site chrome)import { notFound } from "next/navigation"import { MlsSheet } from "@pandaidx/widgets/client"import { fetchListingSheet } from "@pandaidx/widgets/server"export default async function ListingSheetPage({ params }: { params: Promise<{ listingId: string }> }) {const { listingId } = await paramsconst data = await fetchListingSheet({ publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL, listingId })if (!data) notFound()return <MlsSheet listing={data.listing} application={data.application} />}
Examples
Your own printable sheet from the typed data (branded header, two columns of fields, compliance at the bottom)
// app/(print)/mls/[listingId]/sheet/page.tsx (Server Component, no site chrome)import { notFound } from "next/navigation"import { MlsSheetRoot, MlsSheetCompliance, MlsSheetPrint } from "@pandaidx/widgets/client"import { getListingSheet } from "@pandaidx/widgets/server"export default async function SheetPage({ params }: { params: Promise<{ listingId: string }> }) {const { listingId } = await paramsconst data = await getListingSheet({ publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL, listingId })if (!data) notFound()const { sheet } = datareturn (<MlsSheetRoot className="mx-auto max-w-4xl p-8"><header className="flex items-end justify-between border-b pb-4"><div><h1>{sheet.address}</h1><p>{sheet.price} · MLS# {sheet.mlsNumber}</p></div><MlsSheetPrint /></header>{sheet.sections.map((section) => (<section key={section.id} data-mls-sheet-section className="mt-6"><h2>{section.title}</h2><dl className="grid grid-cols-2 gap-x-8 gap-y-1">{section.fields.map((field) => <div key={field.key}><dt className="inline font-semibold">{field.label}: </dt><dd className="inline">{field.value}</dd></div>)}</dl></section>))}<footer className="mt-8"><p>Prepared by {sheet.preparedBy.name}</p><MlsSheetCompliance compliance={sheet.compliance} /></footer></MlsSheetRoot>)}
API reference
MlsSheet
The printable MLS sheet of a listing (Panda /mls/<id>/sheet, linked by the panda listing detail): Back to Listing / Print toolbar, photo + price + address header, General, Location, Rooms, Financial, Additional and Remarks sections, and the "Prepared by" footer with the site logo and the MLS disclaimer. Public fields only. Render it on a page without the site header/footer.
Import from @pandaidx/widgets/client
| Prop | Type | Default | Description |
|---|---|---|---|
| listing* | object | — | Listing with the sheet fields. |
| application* | object | — | Public application (prepared-by name, logo). |
| 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). |
Parts
<MlsSheetCompliance />requiredRequired: the Listing by <office> courtesy line, the feed's disclaimer and the accuracy / consumer-use notices. Pass compliance={sheet.compliance}.
<MlsSheetPrint />Print button (window.print()), hidden when printing. label or your own children.
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.
fetchListingSheet()widget loaderListing (GET /v1/listings/:id?view=sheet: the detail fields plus the sheet's public RESO fields) + public application; null when the listing does not exist (call notFound()). Returns ListingDetailData | null → listing, application
getListingSheet()typed dataTyped printable sheet for a page you design yourself: sheet = { title, address, price, mlsNumber, status, forSale, photo, photos, sections: [{ id, title, fields: [{ key, label, value, href? }] }], preparedBy: { name, logo, phone, email }, compliance } built from the public RESO fields (empty fields left out; the field mapping and labels live in the kernel, so a fix reaches every site) + the raw listing / application. Render it inside <MlsSheetRoot> and keep <MlsSheetCompliance compliance={sheet.compliance} />: publishing requires it. Use MlsSheet for the Panda sheet as is.