MKT UI

Quick start

Prerequisites, registry setup, and installing your first section.

Prerequisites

MKT UI sections are plain React. They are tested against the combination below; other recent versions very likely work, but this is what is actually verified.

RequirementVerified version
React19.2
TypeScript5.9
Tailwind CSS4.3
shadcn CLI4.21
Node.js20.9+

You need a project that already has Tailwind CSS v4 and shadcn initialised. If you do not, run this first:

npx shadcn@latest init

Sections are framework-neutral: no next/link, no next/image, no routing, no server actions. They work in Next.js, Vite, React Router, or Astro. A lint rule in this repository enforces that, so it cannot quietly stop being true.

1. Add the registry

Add the @mkt namespace to your components.json:

components.json
{
  "registries": {
    "@mkt": "http://localhost:3000/r/{name}.json"
  }
}

MKT UI is not published yet

The URL above points at a local development server, because there is no public registry deployment yet. Until there is, run this repository locally (pnpm dev) to install from it, or copy the source straight out of registry/ — every section is a single self-contained file.

2. Install a section

npx shadcn@latest add @mkt/hero-split

That one command also installs everything the section needs: the container, section, cta-group, and media-frame foundations, plus any shadcn primitives. Each section declares its own dependencies, so installing one never pulls in the whole catalog.

3. Add the theme tokens

Sections reference semantic tokens that are not part of stock shadcn. Add them to your global stylesheet:

app/globals.css
@theme inline {
  --color-brand: var(--brand);
  --color-brand-foreground: var(--brand-foreground);
  --color-brand-subtle: var(--brand-subtle);
  --color-brand-border: var(--brand-border);
  --color-surface: var(--surface);
  --color-surface-foreground: var(--surface-foreground);
  --color-success: var(--success);
  --color-success-foreground: var(--success-foreground);
  --color-success-subtle: var(--success-subtle);
}

@theme {
  --container-mkt: 80rem;
  --container-mkt-narrow: 56rem;
  --container-mkt-prose: 44rem;

  --text-display: 2.75rem;
  --text-display--line-height: 1.08;
  --text-display--letter-spacing: -0.027em;

  --text-display-lg: 3.5rem;
  --text-display-lg--line-height: 1.04;
  --text-display-lg--letter-spacing: -0.032em;

  --text-title: 2rem;
  --text-title--line-height: 1.15;
  --text-title--letter-spacing: -0.02em;

  --text-lead: 1.1875rem;
  --text-lead--line-height: 1.6;
  --text-lead--letter-spacing: -0.006em;
}

:root {
  --brand: oklch(0.514 0.222 16.935);
  --brand-foreground: oklch(0.99 0 0);
  --brand-subtle: oklch(0.969 0.019 17.585);
  --brand-border: oklch(0.892 0.058 17.585);

  --surface: oklch(0.977 0.002 265);
  --surface-foreground: oklch(0.145 0 0);

  --success: oklch(0.52 0.122 158);
  --success-foreground: oklch(0.99 0 0);
  --success-subtle: oklch(0.962 0.03 158);
}

See Theming for what each token controls and how to make it yours.

4. Use it

app/page.tsx
import { Button } from "@/components/ui/button";
import { HeroSplit } from "@/components/hero-split";

export default function Page() {
  return (
    <HeroSplit
      eyebrow="Licensed & insured"
      title="Plumbing problems fixed properly, the first time."
      description="Same-day emergency slots across north Austin, upfront pricing, and a six-year workmanship warranty."
      actions={
        <>
          <Button asChild>
            <a href="#quote">Request a quote</a>
          </Button>
          <Button variant="outline" asChild>
            <a href="tel:+15125550142">Call (512) 555-0142</a>
          </Button>
        </>
      }
      note="Free quotes · No call-out fee on scheduled work"
      image={{ src: "/hero.jpg", alt: "Technician fitting a copper pipe" }}
    />
  );
}

Where files land

The shadcn CLI places files using your components.json aliases and rewrites the imports to match:

Registry typeInstalls toExample
registry:blockaliases.componentscomponents/hero-split.tsx
registry:componentaliases.componentscomponents/container.tsx
registry:hookaliases.hookshooks/use-form-submission.ts
registry:uialiases.uicomponents/ui/button.tsx

Server and client rendering

Most sections render on the server and ship no JavaScript. The ones that need interaction carry their own "use client" boundary, so you can drop them into a server component without wrapping anything yourself.

SectionBoundary
hero-split, services-icon-grid, cta-band, site-footerServer
site-headerClient (mobile drawer state)
quote-request-formClient (form state)

Next steps

On this page