CategoriesAllHeroNavigationFooterCall-to-ActionsFeature SectionsTestimonialsPricingContactGalleryStatsFAQServicesNewsletterAuthMiscellaneousButtons
All Components3D Cube InteractionBorder Logo GridCountdownFlip ButtonExpandable FAQsFlow ButtonGlow ButtonGrayscale CarouselInertia Zoom ParallaxLogo Cloud GridMobile Drawer NavigationPixel PreloaderProject GalleryRing ButtonShowcase CarouselSlide PreloaderSliding Stairs PreloaderStormtrooper FAQText Gradient OpacityThreads ButtonTilt HeadlineUltra Preloader
Code
app/page.tsx
1import Faqs from "@/sections/faqs";
2
3const Home = () => {
4  return (
5    <main className="min-h-screen w-full flex items-center justify-center">
6      <Faqs />
7    </main>
8  );
9}
10
11export default Home;Installation
Initialized a project and installed the necessary dependencies to use this component.
1. Initialize a new Next.js project:
npx create-next-app@latest my-app2. Install Framer Motion
npm install framer-motion3. Initialize Shadcn UI
npx shadcn@latest init4. Install Shadcn Components
npx shadcn@latest add accordion buttonAdd FAQ Section
src/sections/faq.tsx
1"use client"
2
3import {
4    Accordion,
5    AccordionContent,
6    AccordionItem,
7    AccordionTrigger,
8} from "@/components/ui/accordion";
9import { Button } from "@/components/ui/button";
10import { faqData } from "@/constants";
11
12import { motion } from "framer-motion";
13import { useState } from "react";
14
15const Faqs = () => {
16    const [open, setOpen] = useState(false);
17
18    return (
19        <section className=" w-full py-20">
20            <div className=" container mx-auto px-4 md:px-0 flex flex-col items-center">
21                <motion.div
22                    initial={false}
23                    animate={open ? "open" : "closed"}
24                    style={{
25                        overflow: "hidden",
26                    }}
27                    variants={{
28                        open: {
29                            height: "fit-content",
30                        },
31                        closed: {
32                            height: 380,
33                        },
34                    }} className=" relative w-full h-fit mt-12">
35
36                    <Accordion
37                        type="single"
38                        collapsible
39                        className="w-full max-w-3xl mx-auto"
40                        defaultValue="item-1"
41                    >
42            {faqData.map((faq, index) => (
43              <AccordionItem key={index} value={faq.id}>
44                                <AccordionTrigger>{faq.question}</AccordionTrigger>
45                                <AccordionContent className="flex flex-col gap-4 text-balance">
46                                    {faq.answer}
47                                </AccordionContent>
48                            </AccordionItem>
49                        ))}
50                    </Accordion>
51                    <motion.div
52                        variants={{
53                            open: {
54                                bottom: "0%",
55                                zIndex: -10,
56                            },
57                            closed: {
58                                bottom: "0%",
59                            },
60                        }}
61                        className="absolute inset-x-0 bottom-0 left-0 right-0 bg-gradient-to-b from-transparent to-background h-1/2"
62                    />
63                </motion.div>
64                <Button variant="secondary" onClick={() => setOpen((pv: boolean) => !pv)} className="mt-4 w-fit">
65                    {open ? (
66                        <>
67                            <p>Show less</p>
68                        </>
69                    ) : (
70                        <>
71                            <p>Show all FAQs</p>
72                        </>
73                    )}
74                </Button>
75            </div>
76        </section >
77    );
78}
79
80export default Faqs;Add Accordion Component
src/components/ui/accordion.tsx
1"use client"
2
3import * as AccordionPrimitive from "@radix-ui/react-accordion"
4import { Plus } from "lucide-react"
5import * as React from "react"
6
7import { cn } from "@/lib/utils"
8
9function Accordion({
10  ...props
11}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
12  return <AccordionPrimitive.Root data-slot="accordion" {...props} />
13}
14
15function AccordionItem({
16  className,
17  ...props
18}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
19  return (
20    <AccordionPrimitive.Item
21      data-slot="accordion-item"
22      className={cn("border-b first:border-t last:border-b-0", className)}
23      {...props}
24    />
25  )
26}
27
28function AccordionTrigger({
29  className,
30  children,
31  ...props
32}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
33  return (
34    <AccordionPrimitive.Header className="flex">
35      <AccordionPrimitive.Trigger
36        data-slot="accordion-trigger"
37        className={cn(
38          "cursor-pointer focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-base md:text-lg font-medium transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-45",
39          className
40        )}
41        {...props}
42      >
43        {children}
44        <Plus className=" text-white pointer-events-none size-5 shrink-0 translate-y-0.5 transition-transform duration-200" />
45      </AccordionPrimitive.Trigger>
46    </AccordionPrimitive.Header>
47  )
48}
49
50function AccordionContent({
51  className,
52  children,
53  ...props
54}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
55  return (
56    <AccordionPrimitive.Content
57      data-slot="accordion-content"
58      className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm md:text-[15px] text-white/70"
59      {...props}
60    >
61      <div className={cn("pt-0 pb-4", className)}>{children}</div>
62    </AccordionPrimitive.Content>
63  )
64}
65
66export { Accordion, AccordionContent, AccordionItem, AccordionTrigger }Add Button Component
src/components/ui/button.tsx
1import * as React from "react"
2import { Slot } from "@radix-ui/react-slot"
3import { cva, type VariantProps } from "class-variance-authority"
4
5import { cn } from "@/lib/utils"
6
7const buttonVariants = cva(
8  "inline-flex items-center cursor-pointer justify-center gap-2 whitespace-nowrap rounded-full text-[15px] font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9  {
10    variants: {
11      variant: {
12        default:
13          "bg-primary text-primary-foreground hover:bg-primary/90",
14        destructive:
15          "bg-destructive text-white hover:bg-destructive/90",
16        outline:
17          "border border-white/15 text-white/80 bg-background hover:border-white/25 hover:text-white",
18        secondary:
19          "bg-secondary text-secondary-foreground hover:bg-secondary/80",
20        ghost:
21          "text-white/70 hover:text-white",
22        link: "text-primary underline-offset-4 hover:underline",
23      },
24      size: {
25        default: " h-8 md:h-9 px-2.5 md:px-4 py-2 has-[>svg]:px-3",
26        sm: " h-7 md:h-8 text-sm rounded-full gap-1.5 px-3 has-[>svg]:px-2.5",
27        lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28        icon: "size-8",
29      },
30    },
31    defaultVariants: {
32      variant: "default",
33      size: "default",
34    },
35  }
36)
37
38function Button({
39  className,
40  variant,
41  size,
42  asChild = false,
43  ...props
44}: React.ComponentProps<"button"> &
45  VariantProps<typeof buttonVariants> & {
46    asChild?: boolean
47  }) {
48  const Comp = asChild ? Slot : "button"
49
50  return (
51    <Comp
52      data-slot="button"
53      className={cn(buttonVariants({ variant, size, className }))}
54      {...props}
55    />
56  )
57}
58
59export { Button, buttonVariants }Add Constants
src/constants/index.ts
1export const faqData = [
2  {
3    id: "item-1",
4    question: "What is Astrae?",
5    answer:
6      "Astrae is a modern landing page template designed for startups, SaaS, and businesses to create stunning websites quickly.",
7  },
8  {
9    id: "item-2",
10    question: "How do I use Astrae?",
11    answer:
12      "You can use Astrae by downloading the template files and integrating them into your project. Detailed documentation is available.",
13  },
14  {
15    id: "item-3",
16    question: "Is Astrae free?",
17    answer:
18      "Astrae offers both free and premium versions. The free version includes basic features, while the premium version unlocks advanced functionalities.",
19  },
20  {
21    id: "item-4",
22    question: "Can I customize Astrae?",
23    answer:
24      "Yes, Astrae is fully customizable. You can modify styles, layouts, and content to fit your brand's needs.",
25  },
26  {
27    id: "item-5",
28    question: "What happens after I subscribe?",
29    answer:
30      "After subscribing, you'll get instant access to all premium templates, components, and resources. You'll also receive a welcome email with your download links and getting started guide.",
31  },
32  {
33    id: "item-6",
34    question: "Can I cancel anytime?",
35    answer:
36      "Yes, you can cancel your subscription at any time. There are no long-term commitments, and you'll retain access to all downloaded templates even after cancellation.",
37  },
38  {
39    id: "item-7",
40    question: "Do I get access to future templates too?",
41    answer:
42      "Absolutely! Your subscription includes all future template releases. We regularly add new templates and components, and you'll get access to everything as long as your subscription is active.",
43  },
44  {
45    id: "item-8",
46    question: "Can I use the templates for client projects?",
47    answer:
48      "Yes, you can use Astrae templates for client projects. Our license allows commercial use, including client work, freelance projects, and agency services without any additional fees.",
49  },
50  {
51    id: "item-9",
52    question: "Do you offer refunds?",
53    answer:
54      "We offer a 30-day money-back guarantee. If you're not satisfied with your purchase for any reason, contact our support team within 30 days for a full refund.",
55  },
56];Add Global Styles
app/globals.css
1@import "tailwindcss";
2@import "tw-animate-css";
3
4@custom-variant dark (&:is(.dark *));
5
6@theme inline {
7  --color-background: var(--background);
8  --color-foreground: var(--foreground);
9  --font-sans: var(--font-geist-sans);
10  --font-mono: var(--font-geist-mono);
11  --color-sidebar-ring: var(--sidebar-ring);
12  --color-sidebar-border: var(--sidebar-border);
13  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
14  --color-sidebar-accent: var(--sidebar-accent);
15  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
16  --color-sidebar-primary: var(--sidebar-primary);
17  --color-sidebar-foreground: var(--sidebar-foreground);
18  --color-sidebar: var(--sidebar);
19  --color-chart-5: var(--chart-5);
20  --color-chart-4: var(--chart-4);
21  --color-chart-3: var(--chart-3);
22  --color-chart-2: var(--chart-2);
23  --color-chart-1: var(--chart-1);
24  --color-ring: var(--ring);
25  --color-input: var(--input);
26  --color-border: var(--border);
27  --color-destructive: var(--destructive);
28  --color-accent-foreground: var(--accent-foreground);
29  --color-accent: var(--accent);
30  --color-muted-foreground: var(--muted-foreground);
31  --color-muted: var(--muted);
32  --color-secondary-foreground: var(--secondary-foreground);
33  --color-secondary: var(--secondary);
34  --color-primary-foreground: var(--primary-foreground);
35  --color-primary: var(--primary);
36  --color-popover-foreground: var(--popover-foreground);
37  --color-popover: var(--popover);
38  --color-card-foreground: var(--card-foreground);
39  --color-card: var(--card);
40  --radius-sm: calc(var(--radius) - 4px);
41  --radius-md: calc(var(--radius) - 2px);
42  --radius-lg: var(--radius);
43  --radius-xl: calc(var(--radius) + 4px);
44}
45
46:root {
47  --radius: 0.625rem;
48  --background: oklch(0% 0 0);
49  --foreground: oklch(0.985 0 0);
50  --card: oklch(0.205 0 0);
51  --card-foreground: oklch(0.985 0 0);
52  --popover: oklch(15.43% 0 0);
53  --popover-foreground: oklch(0.985 0 0);
54  --primary: oklch(100% 0.00011 271.152);
55  --primary-foreground: oklch(0.205 0 0);
56  --secondary: oklch(0.269 0 0);
57  --secondary-foreground: oklch(0.985 0 0);
58  --muted: oklch(19.13% 0 0);
59  --muted-foreground: oklch(0.708 0 0);
60  --accent: oklch(55.9% 0.238 260.78);
61  --accent-foreground: oklch(0.985 0 0);
62  --destructive: oklch(59.56% 0.234 24.23);
63  --border: oklch(1 0 0 / 10%);
64  --input: oklch(1 0 0 / 15%);
65  --ring: oklch(0.556 0 0);
66  --chart-1: oklch(0.488 0.243 264.376);
67  --chart-2: oklch(0.696 0.17 162.48);
68  --chart-3: oklch(0.769 0.188 70.08);
69  --chart-4: oklch(0.627 0.265 303.9);
70  --chart-5: oklch(0.645 0.246 16.439);
71  --sidebar: oklch(0.205 0 0);
72  --sidebar-foreground: oklch(0.985 0 0);
73  --sidebar-primary: oklch(0.488 0.243 264.376);
74  --sidebar-primary-foreground: oklch(0.985 0 0);
75  --sidebar-accent: oklch(0.269 0 0);
76  --sidebar-accent-foreground: oklch(0.985 0 0);
77  --sidebar-border: oklch(1 0 0 / 10%);
78  --sidebar-ring: oklch(0.556 0 0);
79}
80
81.dark {
82  --background: oklch(0% 0 0);
83  --foreground: oklch(0.985 0 0);
84  --card: oklch(0.205 0 0);
85  --card-foreground: oklch(0.985 0 0);
86  --popover: oklch(15.43% 0 0);
87  --popover-foreground: oklch(0.985 0 0);
88  --primary: oklch(100% 0.00011 271.152);
89  --primary-foreground: oklch(0.205 0 0);
90  --secondary: oklch(0.269 0 0);
91  --secondary-foreground: oklch(0.985 0 0);
92  --muted: oklch(19.13% 0 0);
93  --muted-foreground: oklch(0.708 0 0);
94  --accent: oklch(55.9% 0.238 260.78);
95  --accent-foreground: oklch(0.985 0 0);
96  --destructive: oklch(59.56% 0.234 24.23);
97  --border: oklch(1 0 0 / 10%);
98  --input: oklch(1 0 0 / 15%);
99  --ring: oklch(0.556 0 0);
100  --chart-1: oklch(0.488 0.243 264.376);
101  --chart-2: oklch(0.696 0.17 162.48);
102  --chart-3: oklch(0.769 0.188 70.08);
103  --chart-4: oklch(0.627 0.265 303.9);
104  --chart-5: oklch(0.645 0.246 16.439);
105  --sidebar: oklch(0.205 0 0);
106  --sidebar-foreground: oklch(0.985 0 0);
107  --sidebar-primary: oklch(0.488 0.243 264.376);
108  --sidebar-primary-foreground: oklch(0.985 0 0);
109  --sidebar-accent: oklch(0.269 0 0);
110  --sidebar-accent-foreground: oklch(0.985 0 0);
111  --sidebar-border: oklch(1 0 0 / 10%);
112  --sidebar-ring: oklch(0.556 0 0);
113}
114
115@layer base {
116  * {
117    @apply border-border outline-ring/50;
118  }
119  body {
120    @apply bg-background text-foreground;
121  }
122}