All templates
SaaS

NexSupport — Next.js AI Customer Support SaaS Template

Production-ready Next.js 15 SaaS template for AI customer support tools. Dark mode, Tailwind v4, shadcn/ui, Motion animations, full dashboard and landing page included.

Secure checkout via Gumroad
NexSupport — Next.js AI Customer Support SaaS Template preview

Overview

NexSupport is a full-stack Next.js SaaS UI template purpose-built for AI customer support products — think Intercom meets ChatGPT, with a real analytics layer on top. If you're building a ticket automation tool, an AI inbox assistant, a chatbot-as-a-service product, or any B2B SaaS in the support automation space, this template gives you a production-ready foundation with zero design debt. The landing page includes a live-animated chat widget hero, a feature grid, metrics counters, testimonials, FAQ, a full pricing section with monthly/annual toggle, and a conversion-focused CTA — all wired to a single config.tsx file so you can rebrand and relaunch in under an hour.

The dashboard is where NexSupport stands apart from generic SaaS starters. It ships with five fully built pages: an overview with KPI cards, area charts, and a real-time ticket table; a conversations panel with a split-view thread browser and animated chat bubbles; a ticket analytics page with stacked bar charts, a donut chart, sentiment bars, and a sortable table; a usage metrics page with token consumption trends, cost history, and intent rankings; and a visual chatbot builder with drag-and-drop flow steps powered by Framer Motion's Reorder API. Every dashboard page uses shadcn/ui components, recharts for data visualization, and Tailwind v4 CSS variables for consistent theming across all surfaces.

The entire template is dark-mode-only, using a hand-tuned oklch color system (Cyber Teal / Deep Navy) that reads as modern and trustworthy — appropriate for B2B enterprise buyers without feeling sterile. Every color token, gradient, glow, and shadow is defined as a CSS variable in globals.css and reused consistently across components. There are no hardcoded style values anywhere in the codebase. The template is fully responsive from 320px mobile to 1920px widescreen, ships with per-page generateMetadata for SEO, and is structured to slot directly into a Next.js 15 App Router project with TypeScript strict mode enabled.


Stack

| Layer | Technology | |---|---| | Framework | Next.js 15 (App Router) | | Language | TypeScript | | Styling | Tailwind CSS v4 | | Components | shadcn/ui | | Animation | Motion (motion/react) | | Charts | Recharts | | Icons | lucide-react | | Color system | oklch (dark mode only) | | Font | Geist Sans + Geist Mono |


Project Structure

├── app/
│   ├── layout.tsx                  # Root layout — import globalMetadata here
│   ├── page.tsx                    # Landing page — assemble sections here
│   ├── globals.css                 # Color tokens, gradients, Tailwind config
│   ├── pricing/
│   │   └── page.tsx                # /pricing standalone page
│   └── dashboard/
│       ├── layout.tsx              # Dashboard shell: sidebar + topbar
│       ├── page.tsx                # /dashboard — overview, KPIs, charts
│       ├── conversations/
│       │   └── page.tsx            # Split-view conversation browser
│       ├── tickets/
│       │   └── page.tsx            # Ticket analytics + sortable table
│       ├── builder/
│       │   └── page.tsx            # Chatbot flow builder
│       └── metrics/
│           └── page.tsx            # Usage metrics, token consumption, costs
│
├── components/
│   └── landing/
│     ├── navbar.tsx                  # Sticky navbar with announcement bar
│     ├── hero.tsx                    # Typewriter + animated chat widget hero
│     ├── logos.tsx                   # Social proof logo bar
│     ├── features.tsx                # Asymmetric feature grid
│     ├── how-it-works.tsx            # 3-step section with animated connector
│     ├── metrics.tsx                 # Animated stat counters
│     ├── testimonials.tsx            # Split-panel testimonial carousel
│     ├── faq.tsx                     # Sticky-header FAQ with accordion
│     ├── pricing.tsx                 # Pricing cards (landing section)
│     ├── cta.tsx                     # Final CTA banner
│     └── footer.tsx                  # Footer with status dot
└───── lib/
   ├── config.tsx                      # ← All content lives here
   ├── utils.ts                        # cn() helper (shadcn default)
   └── metadata.tsx                    # Global + per-page metadata / generateMetadata

Quick Start

Install dependencies

npm install

Template files

Drop the template files into your project following the structure above. The key files are:

  • app/globals.css — paste the full contents, replacing the default Tailwind output
  • config.tsx — place at project root or @/lib/config
  • metadata.tsx — place at project root or @/lib/metadata
  • All components/*.tsx files into your components/ folder
  • All app/**/*.tsx pages into the corresponding app/ routes

Assemble the landing page

In app/page.tsx:

import { Navbar }      from "@/components/navbar";
import { Hero }        from "@/components/hero";
import { Logos }       from "@/components/logos";
import { Features }    from "@/components/features";
import { HowItWorks }  from "@/components/how-it-works";
import { Metrics }     from "@/components/metrics";
import { Testimonials }from "@/components/testimonials";
import { Pricing }     from "@/components/pricing";
import { FAQ }         from "@/components/faq";
import { CTA }         from "@/components/cta";
import { Footer }      from "@/components/footer";
import { generateHomeMetadata } from "@/metadata";

export const metadata = generateHomeMetadata();

export default function Home() {
  return (
    <>
      <Navbar />
      <main>
        <Hero />
        <Logos />
        <Features />
        <HowItWorks />
        <Metrics />
        <Testimonials />
        <Pricing />
        <FAQ />
        <CTA />
      </main>
      <Footer />
    </>
  );
}

6. Run it

npm run dev

Open http://localhost:3000.


Customization

Brand & content — config.tsx

Everything visible on the site is exported from config.tsx. No hunting through component files.

| Export | What it controls | |---|---| | siteConfig | Name, URL, OG image, Twitter handle | | heroConfig | Headline, subheadline, badge, CTAs, disclaimer | | featuresConfig | 6 feature cards with icons, descriptions, badges | | pricingConfig | Plan names, prices, features, CTA variants | | faqConfig | All FAQ questions and answers | | testimonialsConfig | 4 testimonial quotes with names and initials | | metricsConfig | Animated stat values and labels | | howItWorksConfig | 3-step process titles and descriptions | | dashboardNav | Sidebar navigation links and icons | | dashboardMockData | KPIs, recent tickets, intent breakdown | | pageMetadata | SEO titles, descriptions, keywords per page |

Example — change the hero headline:

// config.tsx
export const heroConfig = {
  badge: "Now live",
  headline: "Your headline here\nSpan two lines like this.",
  subheadline: "Your subheadline here.",
  primaryCta: { label: "Get started", href: "/signup" },
  secondaryCta: { label: "Watch demo", href: "#demo" },
  disclaimer: "Free forever on Starter",
};

Example — add a pricing plan feature:

// config.tsx — pricingConfig.plans[1].features
features: [
  "5,000 AI tickets / mo",
  "Your new feature here",   // ← just add a string
  ...
],

Colors — globals.css

The entire palette lives in the :root block as oklch values. To change the primary accent from teal to purple:

:root {
  --primary: oklch(0.60 0.22 290);   /* purple */
  --accent:  oklch(0.75 0.18 280);   /* light purple */
  --ring:    oklch(0.60 0.22 290);
  --sidebar-primary: oklch(0.60 0.22 290);
  --sidebar-ring:    oklch(0.60 0.22 290);
  --chart-1: oklch(0.60 0.22 290);
}

Gradients are also variables and update automatically:

--background-image-gradient-primary: radial-gradient(
  ellipse 60% 50% at 50% 0%,
  oklch(0.60 0.22 290 / 18%),   /* match your new primary */
  transparent
);

Swapping icons

All icons come from lucide-react. To swap any icon, find the import in the relevant component and replace:

// Before
import { Bot } from "lucide-react";

// After
import { Sparkles } from "lucide-react";

Browse all available icons at lucide.dev.

Adding a dashboard page

  1. Create app/dashboard/your-page/page.tsx
  2. Add an entry to dashboardNav in config.tsx:
import { YourIcon } from "lucide-react";

export const dashboardNav = [
  // ...existing entries
  {
    label: "Your Page",
    href: "/dashboard/your-page",
    icon: YourIcon,
  },
];
  1. Add metadata in metadata.tsx:
export function generateYourPageMetadata(): Metadata {
  return {
    title: "Your Page — NexSupport",
    description: "...",
    robots: buildRobots(false),
  };
}

SEO Setup

How it works

SEO is handled entirely in metadata.tsx. It exports:

  • globalMetadata — used in app/layout.tsx, sets the default title template and global OG tags
  • One generate*Metadata() function per route — used in each page.tsx

Update your domain

// config.tsx
export const siteConfig = {
  name: "YourProduct",
  url: "https://yourproduct.com",       // ← update this
  ogImage: "https://yourproduct.com/og.png",  // ← and this
  twitterHandle: "@yourhandle",
};

All canonical URLs and OG image paths resolve from siteConfig.url automatically.

Per-page metadata usage

// app/pricing/page.tsx
import { generatePricingMetadata } from "@/metadata";
export const metadata = generatePricingMetadata();
// app/dashboard/page.tsx
import { generateDashboardMetadata } from "@/metadata";
export const metadata = generateDashboardMetadata();

Title template

Page titles follow the pattern "{page title} — {site name}" automatically via:

title: {
  default: pageMetadata.home.title,
  template: `%s — ${siteConfig.name}`,
},

So generatePricingMetadata() returns title: "Pricing" and the browser shows "Pricing — NexSupport".

OG image

Place your OG image at public/og.png (recommended: 1200×630px). The template references it via siteConfig.ogImage. You can generate one with tools like og-image.vercel.app or build a dynamic one with next/og.

Dashboard pages are not indexed

All dashboard routes have robots: buildRobots(false) by default — they won't appear in search results, which is correct behavior for authenticated app pages.


Final Notes

No hardcoded styles. Every color, gradient, shadow, and radius in the template references a CSS variable from globals.css. If you change a token, it updates everywhere.

"use client" is scoped. Only components that use browser APIs, event handlers, or React hooks are marked "use client". Layout, metadata exports, and static sections are server components by default.

Mock data is clearly separated. All demo content (ticket lists, chart data, conversation threads) lives either in config.tsx (under dashboardMockData) or as local const at the top of the relevant page file. Replace with real API calls without touching component markup.

Recharts is client-only. Chart components use ResponsiveContainer, which requires the DOM. They are already inside "use client" components — no extra wrapper needed.

Motion's Reorder API (used in the chatbot builder) requires "use client" and works out of the box. If you need server-side rendering for builder state, store it in a server action or Zustand store.

shadcn/ui components are copied into your project via the CLI (npx shadcn@latest add ...), not imported from a package. They live in components/ui/ and can be styled directly by editing their source files.

Tailwind v4 syntax. This template uses Tailwind v4's @theme inline block in globals.css instead of tailwind.config.ts. Do not create a tailwind.config.ts — it will conflict with the v4 setup.

Tech stack

NextJsTailwindCSSShadcnMotionRecharts

Tags

nextjstailwindsaasaiproductscustomertemplatesupportdashboardautomation

Highlights

Full Next.js 15 source codeAll sections as isolated componentsglobals.css design systemconfig.tsx for easy content editingSEO: metadata, Open Graph, JSON-LDSitemap & robots.txtLifetime updates via GumroadMIT license
$49USD
Secure checkout via Gumroad
Get template