Skip to content

FaqSection Component

Complete FAQ section with tabbed categories, accordion-style questions, and smooth animations. Perfect for addressing common customer questions and reducing support load.

Overview

The FaqSection component creates an organized FAQ section with tabbed navigation, expandable accordion items, and elegant animations. It helps address customer concerns and improves conversion rates by providing instant answers.

Preview

FAQ Section Component Preview

Basic Usage

vue
<template>
  <section>
    <FaqSection />
  </section>
</template>

<script setup lang="ts">
import FaqSection from '@/components/FaqSection.vue'
</script>

Features

📑 Tabbed Categories

  • Organized FAQ categories
  • FaqTabs component integration
  • Smooth tab switching

🪗 Accordion Interface

  • Expandable question items
  • FaqAccordionItem components
  • One-at-a-time expansion

✨ Smooth Animations

  • Hover lift effects
  • Opacity transitions
  • Shadow depth changes
  • Backdrop blur effects

🌍 Internationalization

  • Full i18n support
  • Translatable questions and answers
  • Multi-language tab labels

Component Structure

vue
<template>
  <section id="faq" class="min-h-screen flex items-center justify-center">
    <div class="max-w-3xl mx-auto">
      <!-- Section Header -->
      <h1>{{ $t('faq.title') }}</h1>
      <p>{{ $t('faq.subtitle') }}</p>
      
      <!-- Tab Navigation -->
      <FaqTabs v-model="activeTab" :tabs="tabs" />
      
      <!-- FAQ Items -->
      <div class="space-y-4">
        <FaqAccordionItem
          v-for="question in currentQuestions"
          :key="question.id"
          :question="question.question"
          :is-open="openQuestion === question.id"
          @toggle="toggleQuestion(question.id)"
        >
          <div class="answer-content">
            {{ question.answer }}
          </div>
        </FaqAccordionItem>
      </div>
    </div>
  </section>
</template>

Component API

Props

This component doesn't accept props. Configuration is handled through internal data and i18n.

Events

No custom events are emitted from this component.

Data Properties

PropertyTypeDescription
activeTabstringCurrently active tab
openQuestionstring | nullCurrently open question ID
tabsArrayAvailable FAQ categories

FAQ Data Structure

Tab Configuration

typescript
const tabs = [
  { id: 'general', label: 'General' },
  { id: 'pricing', label: 'Pricing' },
  { id: 'technical', label: 'Technical' },
  { id: 'support', label: 'Support' }
]

Question Structure

typescript
interface FaqQuestion {
  id: string
  question: string
  answer: string
  category: string
}

Internationalization

Configure FAQ content in your i18n files:

json
{
  "faq": {
    "title": "Frequently Asked Questions",
    "subtitle": "Find answers to common questions about ClawPlate",
    "general": {
      "q1": {
        "question": "What is ClawPlate?",
        "answer": "ClawPlate is a modern SaaS boilerplate built with Nuxt 4, Vue 3, and Supabase."
      }
    },
    "pricing": {
      "q1": {
        "question": "What's included in the price?",
        "answer": "You get full source code, documentation, and lifetime updates."
      }
    }
  }
}

State Management

Active Tab Management

typescript
const activeTab = ref('general')

const currentQuestions = computed(() => {
  return faqData.value.filter(q => q.category === activeTab.value)
})

Question Toggle Logic

typescript
const openQuestion = ref<string | null>(null)

const toggleQuestion = (questionId: string) => {
  openQuestion.value = openQuestion.value === questionId ? null : questionId
}

Animation Details

Hover Effects

vue
<div class="transition-all duration-300 ease-out hover:-translate-y-1">
  • Lift effect on hover
  • Smooth 300ms transition
  • Ease-out timing function

Shadow Transitions

vue
:class="{ 
  'shadow-lg': openQuestion === question.id,
  'shadow-sm': openQuestion !== question.id 
}"
  • Dynamic shadow depth based on state
  • Larger shadow when expanded

Answer Content Animation

vue
<div class="transition-opacity duration-300 ease-out"
  :class="{ 
    'opacity-100 bg-gradient-to-br from-white/15 to-white/5 backdrop-blur-sm border border-white/10': isOpen,
    'opacity-0': !isOpen
  }"
>

Styling Details

Section Layout

vue
<section class="min-h-screen flex items-center justify-center h-full lg:w-full w-11/12">
  • Full viewport height
  • Centered content
  • Responsive width (11/12 on mobile, full on large screens)

Typography

vue
<!-- Main title -->
<h1 class="text-gray-800 text-4xl md:text-5xl font-medium text-center mb-2">

<!-- Subtitle -->
<p class="text-center text-gray-800 mb-8">

Answer Styling

vue
<div class="rounded-lg mt-2 px-4 py-4 bg-gradient-to-br from-white/15 to-white/5 backdrop-blur-sm border border-white/10">
  • Gradient background with transparency
  • Backdrop blur effect
  • Subtle border with opacity

Customization

Adding New FAQ Categories

typescript
const tabs = [
  // Existing tabs...
  { id: 'billing', label: 'Billing' },
  { id: 'integrations', label: 'Integrations' }
]

Custom Animation Timing

vue
<!-- Faster animations -->
<div class="transition-all duration-200 ease-out">

<!-- Slower, more dramatic -->
<div class="transition-all duration-500 ease-in-out">

Different Color Schemes

vue
<!-- Blue theme -->
<div class="bg-gradient-to-br from-blue-500/15 to-blue-500/5 border-blue-500/10">

<!-- Green theme -->
<div class="bg-gradient-to-br from-green-500/15 to-green-500/5 border-green-500/10">

Child Components

FaqTabs

Handles tab navigation and switching:

vue
<FaqTabs
  v-model="activeTab"
  :tabs="tabs"
/>

FaqAccordionItem

Individual expandable FAQ items:

vue
<FaqAccordionItem
  :question="question.question"
  :is-open="openQuestion === question.id"
  @toggle="toggleQuestion(question.id)"
>
  <div class="answer-content">
    {{ question.answer }}
  </div>
</FaqAccordionItem>

Accessibility

Keyboard Navigation

  • Tab key navigation through questions
  • Enter/Space to expand/collapse
  • Arrow keys for tab navigation

Screen Reader Support

vue
<section aria-labelledby="faq-title">
  <h1 id="faq-title">{{ $t('faq.title') }}</h1>
  
  <div role="tablist">
    <!-- Tab items -->
  </div>
  
  <div role="tabpanel">
    <!-- FAQ content -->
  </div>
</section>

Focus Management

  • Proper focus indicators
  • Focus trapping within expanded items
  • Logical tab order

SEO Benefits

Structured Data

Consider adding FAQ structured data:

vue
<script setup lang="ts">
const faqStructuredData = {
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is ClawPlate?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "ClawPlate is a modern SaaS boilerplate..."
      }
    }
  ]
}
</script>
vue
<section id="faq">
  <!-- Allows direct linking to FAQ section -->
</section>

Performance Optimization

Computed Properties

typescript
const currentQuestions = computed(() => {
  // Efficient filtering based on active tab
  return faqData.value.filter(q => q.category === activeTab.value)
})

Lazy Loading

Consider lazy loading FAQ data for large sets:

typescript
const { data: faqData } = await useLazyFetch('/api/faq')

Integration Examples

With Search Functionality

vue
<template>
  <div class="mb-8">
    <input 
      v-model="searchQuery"
      type="text"
      placeholder="Search FAQ..."
      class="w-full px-4 py-2 rounded-lg border"
    >
  </div>
  
  <div class="space-y-4">
    <FaqAccordionItem
      v-for="question in filteredQuestions"
      :key="question.id"
    />
  </div>
</template>

With Analytics Tracking

vue
<script setup lang="ts">
const toggleQuestion = (questionId: string) => {
  const wasOpen = openQuestion.value === questionId
  openQuestion.value = wasOpen ? null : questionId
  
  // Track FAQ interactions
  if (!wasOpen) {
    gtag('event', 'faq_expand', {
      event_category: 'engagement',
      event_label: questionId
    })
  }
}
</script>

Dependencies

  • FaqTabs - Tab navigation
  • FaqAccordionItem - Accordion functionality
  • Nuxt i18n - For internationalization
  • Vue 3 - Composition API
  • Tailwind CSS - For styling

Built with love by mhdevfr