Contact Page

The Panda websites /contact page (render it without site chrome): the contact image full height on one side and, on the other, the form assigned to the contact spot with its name and description centered above it…

Complete widgetClient component@pandaidx/widgets 1.14.1

Anatomy

Every piece of Contact Page 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
<ContactPage />complete widget

The Panda websites /contact page (render it without site chrome): the contact image full height on one side and, on the other, the form…

</PandaProvider>

Installation

  1. 1
    npm install <tarball or @pandaidx/widgets>
    Terminal
    npm install https://github.com/pandaidx/panda-widgets/releases/download/v1.14.1/pandaidx-widgets-1.14.1.tgz
  2. 2
    import "@pandaidx/widgets/styles.css" in app/layout.tsx
  3. 3
    Wrap the site in <PandaProvider publicKey apiUrl preset theme> (app/layout.tsx)
  4. 4
    In each page (Server Component) call the widget's server loader, then render the widget with its data
  5. 5
    Allow the images: next.config images.remotePatterns [{ protocol: "https", hostname: "**" }] (listing and blog photos come from several CDNs)

Usage

ContactPage
// app/contact/page.tsx (a route group without header/footer)
import { ContactPage } from "@pandaidx/widgets/client"
import { fetchContactPage } from "@pandaidx/widgets/server"
export default async function Contact() {
const data = await fetchContactPage({ publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL })
return <ContactPage data={data} />
}

Examples

Your own contact page: the side image and heading are yours, the assigned form is Panda's

ContactPage
// app/contact/page.tsx
import Image from "next/image"
import { FormActions, FormFields, FormSuccess, PandaFormRoot } from "@pandaidx/widgets/client"
import { fetchContactPage } from "@pandaidx/widgets/server"
export default async function Contact() {
// data.form: the form assigned to the contact spot (null when none); data.image: the contact image
const data = await fetchContactPage({ publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL })
return (
<main className="grid min-h-dvh lg:grid-cols-2">
<div className="relative min-h-80">
{data.image ? <Image src={data.image} alt="" fill priority sizes="(min-width: 1024px) 50vw, 100vw" className="object-cover" /> : null}
</div>
<section className="mx-auto flex w-full max-w-lg flex-col justify-center px-6 py-16">
<h1 className="text-4xl">{data.form?.name}</h1>
{data.form?.description ? <p className="mt-3 opacity-70">{data.form.description}</p> : null}
<PandaFormRoot form={data.form} source="contact-form" fieldVariant="underline" classNames={{ root: "mt-8" }}>
<FormFields />
<FormActions />
<FormSuccess />
</PandaFormRoot>
</section>
</main>
)
}
// ContactPage is only this layout: image + heading + the PandaForm of the contact spot. Rebuild it with PandaFormRoot instead of restyling its markup.

API reference

ContactPage

The Panda websites /contact page (render it without site chrome): the contact image full height on one side and, on the other, the form assigned to the contact spot with its name and description centered above it (PandaForm in the websites form look), the dashboard empty state when none is assigned, and an X back to the homepage.

Import from @pandaidx/widgets/client · renders inside PandaProvider

PropTypeDefaultDescription
data*object—Assigned form and side image.
showImagebooleantrueSide image column (stacked on top on phones).
imagePosition"left" | "right""left"Side of the image on desktop.
closeHrefstring"/"X link to leave the page; empty hides it.
titlestring—Heading above the form. Default: the form name.
descriptionstring—Copy under the heading. Default: the form description.
formStyle"panda" | "theme""panda"panda: the websites dynamic form look; theme: the PandaForm design of the site theme.
sourcestring"contact-form"Lead source label.
formClassNamesobject—Classes appended to the PandaForm slots (root, input, button…).
preset"default" | "template1"—Preset for this widget only (defaults to the provider preset).
variant"default" | "template1"—Deprecated alias of preset.
themeobject—Token overrides for this widget only, merged over the provider theme (same shape as PandaProvider.theme).

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.

fetchContactPage()widget loader

The form of the contact spot (/v1/forms/contact) and the side image (homepage.contactImage, else the owner's headshot). Returns ContactPageData → data