# Product launch

> A product launch landing page: an announcement banner, a bento grid of highlights, details in tabs and an email sign-up.

Facade UI item `product-launch` (block, template).
Docs page: https://facadeui.dev/components/product-launch · Registry JSON: https://facadeui.dev/r/product-launch.json

## Install

```bash
npx shadcn@latest add @facade/product-launch
```

Or by URL: `npx shadcn@latest add https://facadeui.dev/r/product-launch.json`. The CLI also installs what it needs: @facade/banner, @facade/bento-grid, @facade/faq-accordion, @facade/feature-tabs, @facade/footer, @facade/hero-centered, @facade/nav-top, @facade/newsletter, @facade/types, @facade/usp-list.

Files: `components/templates/product-launch.tsx`

Usage example as an installable item: `npx shadcn@latest add @facade/product-launch-demo` (lands in components/examples/).

## Usage

The source of the preview on the docs page. `./content` holds sample data.

```tsx
"use client"

import { useState } from "react"

import { ProductLaunch } from "@/components/templates/product-launch"
import type { NewsletterStatus } from "@/components/sections/newsletter"

import {
  BENTO,
  FAQS,
  FOOTER_GROUPS,
  NAV_ITEMS,
  TABS,
  USPS,
  MediaPlaceholder,
} from "./content"

export function Demo() {
  const [status, setStatus] = useState<NewsletterStatus>("idle")

  return (
    <div className="-m-6 sm:-m-10">
      <ProductLaunch
        signUpStatus={status}
        signUpError="Enter a valid email address."
        onSignUp={(email) => {
          if (!email.includes("@")) {
            setStatus("error")
            return
          }
          setStatus("submitting")
          window.setTimeout(() => setStatus("success"), 900)
        }}
        content={{
          brand: "Facade UI",
          nav: NAV_ITEMS,
          navActions: [{ label: "Star on GitHub", href: "#github" }],
          announcement: {
            label: "Launch announcement",
            message: "Facade UI v0.1 is out.",
            action: { label: "Read the notes", href: "#release" },
          },
          hero: {
            eyebrow: "Now available",
            title: "Sixty-two pieces, one system",
            description:
              "Sections, atoms, motion and three verified themes. Install what you need; the source is yours.",
            actions: [
              { label: "Get started", href: "#start" },
              { label: "Browse components", href: "#components" },
            ],
            note: "MIT licensed.",
            media: <MediaPlaceholder label="Launch screenshot" ratio="aspect-[16/8]" />,
          },
          highlights: {
            eyebrow: "At a glance",
            title: "What is in the box",
            items: BENTO,
          },
          usps: { eyebrow: "Why", title: "Three things that matter", items: USPS },
          detail: {
            eyebrow: "How it works",
            title: "Three steps, one system",
            items: TABS,
          },
          faq: { eyebrow: "FAQ", title: "Questions, answered", items: FAQS },
          signup: {
            eyebrow: "Changelog",
            title: "One email when something ships",
            description: "No drip campaign, no webinar invitations.",
            note: "Unsubscribe in one click.",
          },
          footer: {
            groups: FOOTER_GROUPS,
            copyright: "© 2026 Facade UI contributors",
            legal: [{ label: "Privacy", href: "#privacy" }],
          },
        }}
      />
    </div>
  )
}
```

## Props

### ProductLaunchProps

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `content` (required) | `ProductLaunchContent` |  |  |
| `link` | `LinkComponent` |  | Unlike the other two templates, this one has no `image` prop. Every image comes through a `media` slot, so pass `<Image />` there directly. |
| `currentPath` | `string` |  |  |
| `onSignUp` | `(email: string) => void` |  | Wire this to your own form action or mutation. |
| `signUpStatus` | `NewsletterStatus` |  |  |
| `signUpError` | `string` |  |  |
