# Faqs 1

> Two-column FAQ with sticky header, scroll-reveal stagger, and registry-native copy.

A shadcn/ui block from the [@nusaiba](https://nusaiba.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/nusaiba/faqs-1).

- Page, with a live preview: https://shadcn.exchange/r/nusaiba/faqs-1
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/nusaiba/faqs-1-light-aa23b218d1e7504e.png
- Registry item: https://nusaiba.dev/r/base-nova/faqs-1.json
- Categories: faqs
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://nusaiba.dev/r/base-nova/faqs-1.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `motion`
- Registry items: `@nusaiba/foundation`, `accordion`

## Files

### `registry/blocks/faqs/faqs-data.ts`

```ts
export const faqSite = {
	name: "Nusaiba",
	namespace: "@nusaiba",
	domain: "nusaiba.dev",
} as const;

export type FaqCategoryId = "install" | "plans" | "customize";

export type FaqItem = {
	id: string;
	category: FaqCategoryId;
	title: string;
	content: string;
};

export const faqCategories: { id: FaqCategoryId; label: string }[] = [
	{ id: "install", label: "Install" },
	{ id: "plans", label: "Plans" },
	{ id: "customize", label: "Customize" },
];

export const faqItems: FaqItem[] = [
	{
		id: "what-is",
		category: "install",
		title: `What is ${faqSite.name}?`,
		content: `${faqSite.name} is an open shadcn registry of motion-first landing sections — heroes, pricing, FAQs, footers, and more. Preview live, install into your repo with the CLI, and keep every file.`,
	},
	{
		id: "landing-pages",
		category: "plans",
		title: "Can I use blocks on a client landing page?",
		content:
			"Yes. Free blocks ship for personal and commercial projects. Pro blocks include a commercial license for client work — install once, edit the copy and tokens, and ship the page you own.",
	},
	{
		id: "install",
		category: "install",
		title: "How do I add a block to my project?",
		content: `Add the ${faqSite.namespace} registry to components.json, then run npx shadcn@latest add ${faqSite.namespace}/block-name. Files land in your codebase — no runtime dependency on ${faqSite.name}.`,
	},
	{
		id: "free-vs-pro",
		category: "plans",
		title: "What's included in Free vs Pro?",
		content:
			"Free blocks cover core landing patterns — hero, features, FAQ, CTA, footer. Pro unlocks advanced motion blocks, registry token install, lifetime updates, and commercial licensing for agency work.",
	},
	{
		id: "customize",
		category: "customize",
		title: "Can I change copy and layout after install?",
		content:
			"Every block is yours to edit. Swap headlines for your product, trim sections, restyle with your tokens, or remove motion — the source lives in your project, not behind a package import.",
	},
	{
		id: "frameworks",
		category: "install",
		title: "Which stacks are supported?",
		content:
			"Any React setup that runs shadcn/ui — Next.js, Vite, Remix, and others. Blocks use your existing components.json aliases and design tokens.",
	},
	{
		id: "motion",
		category: "customize",
		title: "Do animations respect reduced motion?",
		content:
			"Yes. Blocks check prefers-reduced-motion and fall back to static layouts. Motion is packaging — your landing page stays readable when users request less animation.",
	},
	{
		id: "copy-prompt",
		category: "install",
		title: "What is Copy Prompt?",
		content: `Each block page includes a Copy Prompt — a ready-made instruction for Cursor or other AI tools to install and adapt the section. Use it when you want a guided handoff instead of the CLI alone.`,
	},
	{
		id: "tokens",
		category: "customize",
		title: "Will blocks match my brand colors?",
		content:
			"Blocks use semantic tokens — background, foreground, muted, primary — from your globals.css. After install, they inherit your theme without hardcoded palette lock-in.",
	},
	{
		id: "preview",
		category: "install",
		title: "Can I preview before installing?",
		content: `Browse ${faqSite.domain}/blocks, toggle light and dark preview, and read the source explorer. When a section fits your landing page, copy the CLI command or prompt and add it to your repo.`,
	},
];

export const faqSplitHeader = {
	eyebrow: "FAQ",
	title: "Questions before you ship",
	description:
		"Quick answers about installing blocks, Pro licensing, and tailoring sections for your landing page.",
	supportLabel: "Browse the library",
	supportHref: "/blocks",
} as const;

export const faqLandingHeader = {
	eyebrow: "FAQ",
	title: `Questions about ${faqSite.name}`,
	description:
		"Quick answers about the registry, install flow, and what lands in your project after you run the CLI.",
	supportLabel: "Browse the library",
	supportHref: "/blocks",
} as const;

export const faqCenteredHeader = {
	eyebrow: "Support",
	title: "Common questions",
	description:
		"Everything you need to pick blocks, install with shadcn, and ship a polished landing page.",
} as const;

export function faqsByCategory(category: FaqCategoryId) {
	return faqItems.filter((item) => item.category === category);
}
```

### `registry/blocks/faqs/1/faqs-section.tsx`

```tsx
"use client";

import Link from "next/link";
import { useRef } from "react";
import { motion, useInView, useReducedMotion } from "motion/react";
import {
	Accordion,
	AccordionContent,
	AccordionItem,
	AccordionTrigger,
} from "@/components/ui/accordion";
import { motionStagger, motionViewport } from "@/lib/motion-tokens";
import { faqItems, faqSplitHeader } from "../faqs-data";
import { SectionShell, ContentRail } from "@/components/layout-contract";

const spring = { type: "spring" as const, duration: 0.3, bounce: 0 };

export function FaqsSection() {
	const reduceMotion = useReducedMotion();
	const ref = useRef<HTMLElement>(null);
	const inView = useInView(ref, motionViewport);

	const itemVariants = reduceMotion
		? { hidden: { opacity: 1 }, visible: { opacity: 1 } }
		: {
				hidden: { opacity: 0, filter: "blur(4px)", y: 8 },
				visible: { opacity: 1, filter: "blur(0px)", y: 0, transition: spring },
			};

	return (
		<SectionShell spacingMode="section" ref={ref}>
			<ContentRail maxWidth="max-w-5xl" className="grid gap-10 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.25fr)] lg:gap-16">
				<motion.div
					animate={inView ? "visible" : "hidden"}
					className="lg:sticky lg:top-24 lg:self-start"
					initial="hidden"
					variants={{
						hidden: {},
						visible: { transition: { staggerChildren: motionStagger.item, delayChildren: 0.04 } },
					}}
				>
					<motion.p
						className="font-medium text-primary text-xs uppercase tracking-[0.22em]"
						variants={itemVariants}
					>
						{faqSplitHeader.eyebrow}
					</motion.p>
					<motion.h2
						className="mt-3 text-balance font-medium text-2xl tracking-tight md:text-4xl"
						variants={itemVariants}
					>
						{faqSplitHeader.title}
					</motion.h2>
					<motion.p
						className="mt-4 text-pretty text-muted-foreground text-sm leading-relaxed md:text-base"
						variants={itemVariants}
					>
						{faqSplitHeader.description}
					</motion.p>
					<motion.p className="mt-6 text-muted-foreground text-sm" variants={itemVariants}>
						Still deciding?{" "}
						<Link
							className="text-foreground underline-offset-4 hover:underline"
							href={faqSplitHeader.supportHref}
						>
							{faqSplitHeader.supportLabel}
						</Link>
					</motion.p>
				</motion.div>

				<motion.div
					animate={inView ? "visible" : "hidden"}
					initial="hidden"
					variants={{
						hidden: {},
						visible: {
							transition: { staggerChildren: motionStagger.item, delayChildren: 0.08 },
						},
					}}
				>
					<Accordion className="w-full">
						{faqItems.map((item) => (
							<motion.div key={item.id} variants={itemVariants}>
								<AccordionItem value={item.id}>
									<AccordionTrigger className="py-5 text-left hover:no-underline">
										{item.title}
									</AccordionTrigger>
									<AccordionContent className="pb-5 text-muted-foreground text-sm leading-relaxed">
										{item.content}
									</AccordionContent>
								</AccordionItem>
							</motion.div>
						))}
					</Accordion>
				</motion.div>
			</ContentRail>
		</SectionShell>
	);
}
```
