Skip to content
Facade UI
Colour mode
GitHub (opens in a new tab)
blocktemplate

Agency site

A studio site: overlay hero, work grid, process steps, a featured quote and the team.

Preview

Open full width (opens in a new tab)
Preview width

Installation

Package manager
pnpm dlx shadcn@latest add https://facadeui.dev/r/agency.json

Pulls in card-list, cta-band, footer, hero-with-media, logo-cloud, logo-mark, nav-top, stat, stats, steps, team, testimonial, testimonial-single, types. The CLI installs them for you.

Usage

The exact source of the preview above.

demos/agency.tsx
"use client"

/**
 * `"use client"` because the process steps carry icon components and NavTop is
 * a client component — icons cannot cross a server-to-client boundary as props.
 */

import { Agency } from "@registry/templates/agency"

import {
  FOOTER_GROUPS,
  LOGOS,
  NAV_ITEMS,
  POSTS,
  QUOTES,
  STATS,
  STEPS,
  TEAM,
} from "./content"

export function Demo() {
  return (
    <div className="-m-6 sm:-m-10">
      <Agency
        content={{
          brand: "Facade Studio",
          nav: NAV_ITEMS,
          navActions: [{ label: "Start a project", href: "#contact" }],
          hero: {
            eyebrow: "Design and engineering",
            title: "We build the front of the business",
            description:
              "Marketing sites, design systems and the handover that makes them last.",
            actions: [
              { label: "See our work", href: "#work" },
              { label: "Start a project", href: "#contact" },
            ],
            // Decorative: it says nothing the copy does not.
            media: (
              <div
                role="presentation"
                className="size-full bg-[radial-gradient(circle_at_25%_25%,#2f3d5c,transparent_55%),radial-gradient(circle_at_75%_35%,#5c3350,transparent_50%),linear-gradient(150deg,#12151d,#2b2340)]"
              />
            ),
          },
          clients: { title: "Selected clients", items: LOGOS },
          work: {
            eyebrow: "Work",
            title: "Recent projects",
            description: "A few of the sites and systems we have shipped.",
            items: POSTS,
          },
          process: {
            eyebrow: "Process",
            title: "How we work",
            items: STEPS,
          },
          quote: { title: "Client story", item: QUOTES[0]! },
          stats: {
            eyebrow: "Track record",
            title: "In numbers",
            items: STATS.slice(0, 3),
          },
          team: { eyebrow: "Studio", title: "Who you will work with", items: TEAM },
          cta: {
            title: "Have something in mind?",
            description:
              "Tell us what you are building and we will tell you how we would approach it.",
            actions: [{ label: "Start a project", href: "#contact" }],
          },
          footer: {
            groups: FOOTER_GROUPS.slice(0, 2),
            copyright: "© 2026 Facade Studio",
            legal: [{ label: "Privacy", href: "#privacy" }],
          },
        }}
      />
    </div>
  )
}

Source

What the CLI copies into your project, byte for byte.

components/templates/agency.tsx
/**
 * Agency — a studio or agency site, assembled from registry sections.
 *
 * Differs from `SaasLanding` in shape rather than in parts: a centred hero over
 * media, work as a card grid, a process as numbered steps, the people, and one
 * featured quote instead of a wall of them. Agencies sell judgement and people,
 * so the page leads with work and faces rather than with features and pricing.
 *
 * a11y: the same explicit outline discipline — the hero is the page's `<h1>`,
 * every band an `<h2>`, every item an `<h3>`. The hero uses the `overlay`
 * placement, which always paints a scrim, because text over an arbitrary image
 * has no guaranteed contrast ratio.
 *
 * Dependencies: react, @/lib/types, @/components/sections/*.
 */

import type { ReactNode } from "react"

import type { CtaItem, ImageComponent, LinkComponent } from "@/lib/types"
import { CardList, type CardItem } from "@/components/sections/card-list"
import { CtaBand } from "@/components/sections/cta-band"
import { Footer, type FooterGroup, type FooterLink } from "@/components/sections/footer"
import { HeroWithMedia } from "@/components/sections/hero-with-media"
import { LogoCloud } from "@/components/sections/logo-cloud"
import { NavTop, type NavItem } from "@/components/sections/nav-top"
import { Stats } from "@/components/sections/stats"
import { Steps, type StepItem } from "@/components/sections/steps"
import { Team, type TeamMember } from "@/components/sections/team"
import { TestimonialSingle } from "@/components/sections/testimonial-single"
import type { LogoItem } from "@/components/ui/logo-mark"
import type { StatItem } from "@/components/ui/stat"
import type { TestimonialItem } from "@/components/ui/testimonial"

export interface AgencyContent {
  brand: ReactNode
  nav: NavItem[]
  navActions?: CtaItem[]

  hero: {
    eyebrow?: string
    title: string
    description: string
    actions: CtaItem[]
    /** Decorative in overlay placement: give it `alt=""`. */
    media: ReactNode
  }

  clients?: { title?: string; items: LogoItem[] }

  work: {
    eyebrow?: string
    title: string
    description?: string
    items: CardItem[]
  }

  process?: {
    eyebrow?: string
    title: string
    description?: string
    items: StepItem[]
  }

  stats?: { title?: string; eyebrow?: string; items: StatItem[] }

  quote?: { title?: string; item: TestimonialItem }

  team?: {
    eyebrow?: string
    title: string
    description?: string
    items: TeamMember[]
  }

  cta: {
    eyebrow?: string
    title: string
    description?: string
    actions: CtaItem[]
  }

  footer: {
    groups?: FooterGroup[]
    brand?: ReactNode
    copyright?: ReactNode
    legal?: FooterLink[]
  }
}

export interface AgencyProps {
  content: AgencyContent
  image?: ImageComponent
  link?: LinkComponent
  currentPath?: string
  banner?: ReactNode
}

export function Agency({ content, image, link, currentPath, banner }: AgencyProps) {
  const { hero, clients, work, process, stats, quote, team, cta, footer } = content

  return (
    <>
      {banner}

      <NavTop
        brand={content.brand}
        items={content.nav}
        actions={content.navActions}
        link={link}
        currentPath={currentPath}
      />

      <main id="main">
        <HeroWithMedia
          eyebrow={hero.eyebrow}
          title={hero.title}
          description={hero.description}
          actions={hero.actions}
          media={hero.media}
          link={link}
          placement="overlay"
          size="xl"
          headingLevel={1}
          spacing="lg"
        />

        {clients ? (
          <LogoCloud
            title={clients.title}
            items={clients.items}
            image={image}
            link={link}
            headingLevel={2}
            spacing="sm"
          />
        ) : null}

        <CardList
          eyebrow={work.eyebrow}
          title={work.title}
          description={work.description}
          items={work.items}
          image={image}
          link={link}
          headingLevel={2}
          itemHeadingLevel={3}
          columns={3}
        />

        {process ? (
          <Steps
            eyebrow={process.eyebrow}
            title={process.title}
            description={process.description}
            items={process.items}
            headingLevel={2}
            itemHeadingLevel={3}
          />
        ) : null}

        {quote ? (
          <TestimonialSingle
            title={quote.title ?? "Client story"}
            item={quote.item}
            image={image}
            variant="muted"
          />
        ) : null}

        {stats ? (
          <Stats
            eyebrow={stats.eyebrow}
            title={stats.title}
            items={stats.items}
            headingLevel={2}
            variant="divided"
            className="border-y"
          />
        ) : null}

        {team ? (
          <Team
            eyebrow={team.eyebrow}
            title={team.title}
            description={team.description}
            items={team.items}
            image={image}
            link={link}
            headingLevel={2}
            itemHeadingLevel={3}
            shape="circle"
          />
        ) : null}

        <CtaBand
          eyebrow={cta.eyebrow}
          title={cta.title}
          description={cta.description}
          actions={cta.actions}
          link={link}
          headingLevel={2}
          layout="split"
          variant="card"
        />
      </main>

      <Footer
        brand={footer.brand ?? content.brand}
        groups={footer.groups}
        copyright={footer.copyright}
        legal={footer.legal}
        link={link}
        headingLevel={2}
      />
    </>
  )
}

Props

AgencyProps

Props for AgencyProps
PropTypeDefault
content*RequiredAgencyContent
imageImageComponent
linkLinkComponent
currentPathstring
bannerReactNode