Trigger: Use when "section blocks", "lego blocks", "hero block". Next.js + Tailwind + framer-motion blocks. A catalog of production-ready, conversion-optimized TSX section components for local business websites.
Philosophy
Every block follows these non-negotiable principles:
- Self-contained — drop-in component, no cross-dependencies outside the shared stack
- Conversion-first — every visual decision serves a psychological trigger: trust, urgency, authority, social proof, reciprocity, or clarity
- Shortcode-driven — brand variables injected via
{{SHORTCODE}}placeholders. Fill from BRAND.md before shipping - Premium by default — no stock template feel. Dark surfaces, intentional typography, precise spacing
- Mobile-first — every block is responsive. Desktop enhances; mobile converts
The Stack
All blocks are written for:
- Next.js 16+ (App Router compatible, Turbopack)
- Tailwind CSS v4 — see architecture rule below
- framer-motion v12+ (npm i framer-motion)
- lucide-react (npm i lucide-react)
- TypeScript
CRITICAL ARCHITECTURE RULE — Named CSS Classes (NOT Raw Tailwind Utilities)
Tailwind 4 with Turbopack does NOT scan utility classes from large agent-generated files. This means raw Tailwind utilities in className will NOT be in the compiled CSS and the page will render completely unstyled.
DO — Named CSS Classes:
<section className="hero">
<div className="hero__inner">
<h1 className="hero-headline">Tampa Bay's Most Trusted Roofer</h1>
<a href="#" className="btn-primary-cta">Get Free Inspection</a>
</div>
</section>
/* In globals.css — statically defined, always included */
.hero { background-color: var(--color-primary); min-height: 90vh; }
.hero__inner { max-width: 1280px; margin: 0 auto; padding: 8rem 1.5rem; }
.hero-headline { font-size: clamp(2.5rem, 6vw, 4.5rem); color: #ffffff; font-weight: 900; }
.btn-primary-cta { background-color: var(--color-accent); padding: 1rem 2rem; border-radius: 1rem; }
DO NOT — Raw Tailwind utilities for layout/color/spacing (these will NOT render in Tailwind 4 + Turbopack if generated by an agent):
<section className="bg-[#1a2744] min-h-[90vh]">
<div className="max-w-7xl mx-auto px-6 py-32">
What IS safe to use inline: Standard responsive utilities that exist in Tailwind's default config — hidden, block, flex, grid, sm:block, md:flex, lg:grid, lg:hidden, sm:flex.
CSS Variables Pattern
Always define brand colors as CSS variables in globals.css:
:root {
--color-primary: #1a2744;
--color-primary-dark: #0d1526;
--color-accent: #e8441a;
--color-accent-hover: #d03a15;
--max-width: 1280px;
}
Then reference them in named CSS classes. Never hardcode hex values in JSX className attributes.
framer-motion Rules for Section Blocks
- Hero content: NO
initial={{ opacity: 0 }}on hero elements — they must be visible on page load - Below-fold whileInView: Safe to use
initial={{ opacity: 1, y: 20 }}withwhileInView={{ opacity: 1, y: 0 }} - NEVER use
initial={{ opacity: 0 }}with whileInView — content will be invisible until user scrolls - Mobile menus and accordions:
initial={{ opacity: 0, height: 0 }}is correct for collapsed state
globals.css @source Directive
Always include at the top of globals.css to ensure Tailwind scans source files:
@import "tailwindcss";
@source "../../**/*.{ts,tsx,js,jsx}";
Shortcode Reference
| Shortcode | Description | Example |
|---|---|---|
| {{BUSINESS_NAME}} | Full business name | "Apex Roofing & Restoration" |
| {{HERO_HEADLINE}} | Primary H1 — conversion-focused | "Roof Replacement Done Right the First Time" |
| {{HERO_SUBHEADLINE}} | Supporting sentence under H1 | "Sarasota's most trusted roofing crew since 2009" |
| {{PHONE}} | Click-to-call phone number | "(941) 555-1234" |
| {{CTA_PRIMARY}} | Primary button text | "Get a Free Estimate" |
| {{TRUST_STATEMENT}} | Short trust line | "Licensed • Insured • 5-Star Rated" |
| {{YEARS_IN_BUSINESS}} | Years operating | "15" |
| {{REVIEW_COUNT}} | Total review count | "400+" |
| {{STAR_RATING}} | Average star rating | "4.9" |
| {{JOBS_COMPLETED}} | Total jobs done | "2,400+" |
| {{CITY}} | Primary city served | "Sarasota" |
| {{FOUNDED_YEAR}} | Year founded | "2009" |
| {{TAGLINE}} | Brand tagline | "Built Tough. Done Right." |
Block Catalog
| Category | Blocks | |----------|--------| | Hero Blocks | hero-dominant, hero-split, hero-statement, hero-form | | Trust Blocks | trust-bar, trust-badges, reviews-strip, reviews-featured, stats-row | | Service Blocks | services-grid-3, services-list, services-featured, services-tabs | | Process Blocks | process-steps, process-timeline | | CTA Blocks | cta-banner, cta-sticky-header, cta-footer-form | | Social Proof Blocks | proof-logos, proof-before-after, proof-case-study | | Local / Geo Blocks | areas-grid, areas-map-placeholder, local-trust | | Content Blocks | faq-accordion, about-split, guarantee-block |
Animation Standards — Required Pattern
NEVER use this pattern (causes blank page on load):
// BAD — entire section invisible until scroll triggers
const ref = useRef(null)
const isInView = useInView(ref, { once: true })
return (
<motion.div ref={ref} initial={{ opacity: 0, y: 40 }}
animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 40 }}>
ALWAYS use this pattern instead:
// GOOD — uses whileInView prop, no refs needed, content visible in DOM
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5, ease: "easeOut" }}
>
Hero Section Exception — NO animations. Hero content (H1, subheadline, CTAs, trust bar) must NEVER use initial opacity animations. Hero content must be visible immediately on page load. Use static rendering for all above-the-fold content.
Page Assembly Recipes
Homepage — Home Services (Roofing, HVAC, Plumbing): HeroDominant → TrustBar → ServicesGrid3 → StatsRow → ReviewsStrip → ProcessSteps → CtaBanner → FaqAccordion → CtaFooterForm
Homepage — Premium / Professional Services (Law, Med Spa, Finance): HeroStatement → TrustBadges → ServicesGrid3 → ReviewsFeatured → ProcessSteps → GuaranteeBlock → CtaBanner → FaqAccordion → CtaFooterForm
Homepage — Multi-Service Contractor (Landscaping, Cleaning, Restoration): HeroSplit → TrustBar → ServicesFeatured → StatsRow → ProofBeforeAfter → ReviewsStrip → LocalTrust → CtaFooterForm
Service Page (Individual Service): HeroSplit → TrustBar → FaqAccordion → ReviewsStrip → CtaBanner
About Page: HeroStatement → StatsRow → AboutSplit → ReviewsFeatured → TrustBadges → CtaFooterForm
Contact / Estimate Page: HeroStatement → TrustBar → CtaFooterForm → ReviewsStrip
Service Area Page (City Landing Page): HeroSplit → TrustBar → ServicesGrid3 → ReviewsStrip → LocalTrust → CtaBanner