Accordion Components

Beautiful, responsive accordion components built with TailwindCSS and AlpineJS. Perfect for FAQs, collapsible content, and expandable sections.

1. Basic Accordion

A simple, clean accordion perfect for FAQs or basic content organization.

TailwindCSS is a utility-first CSS framework that provides low-level utility classes to build custom designs directly in your markup.

Start by installing TailwindCSS via npm or including it via CDN. Then begin using utility classes in your HTML.

Yes! TailwindCSS includes responsive variants for almost every utility class, making it easy to build responsive designs.

<div x-data="{ open: null }" class="space-y-2">
    <div class="bg-white border border-gray-200 shadow-sm rounded-lg">
        <button @click="open = open === 1 ? null : 1" class="w-full px-6 py-4 text-left font-semibold flex justify-between items-center hover:bg-gray-50 transition-colors">
            <span>What is TailwindCSS?</span>
            <svg class="w-5 h-5 transform transition-transform" :class="{'rotate-180': open === 1}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
            </svg>
        </button>
        <div x-show="open === 1" x-collapse>
            <div class="px-6 py-4 border-t border-gray-200 bg-gray-50">
                <p class="text-gray-700">TailwindCSS is a utility-first CSS framework that provides low-level utility classes to build custom designs directly in your markup.</p>
            </div>
        </div>
    </div>
    
    <div class="bg-white border border-gray-200 shadow-sm rounded-lg">
        <button @click="open = open === 2 ? null : 2" class="w-full px-6 py-4 text-left font-semibold flex justify-between items-center hover:bg-gray-50 transition-colors">
            <span>How do I get started?</span>
            <svg class="w-5 h-5 transform transition-transform" :class="{'rotate-180': open === 2}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
            </svg>
        </button>
        <div x-show="open === 2" x-collapse>
            <div class="px-6 py-4 border-t border-gray-200 bg-gray-50">
                <p class="text-gray-700">Start by installing TailwindCSS via npm or including it via CDN. Then begin using utility classes in your HTML.</p>
            </div>
        </div>
    </div>

    <div class="bg-white border border-gray-200 shadow-sm rounded-lg">
        <button @click="open = open === 3 ? null : 3" class="w-full px-6 py-4 text-left font-semibold flex justify-between items-center hover:bg-gray-50 transition-colors">
            <span>Is it responsive by default?</span>
            <svg class="w-5 h-5 transform transition-transform" :class="{'rotate-180': open === 3}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
            </svg>
        </button>
        <div x-show="open === 3" x-collapse>
            <div class="px-6 py-4 border-t border-gray-200 bg-gray-50">
                <p class="text-gray-700">Yes! TailwindCSS includes responsive variants for almost every utility class, making it easy to build responsive designs.</p>
            </div>
        </div>
    </div>
</div>
<template>
  <div class="space-y-2">
    <div class="bg-white border border-gray-200 shadow-sm rounded-lg">
      <button 
        @click="toggleAccordion(1)" 
        class="w-full px-6 py-4 text-left font-semibold flex justify-between items-center hover:bg-gray-50 transition-colors">
        <span>What is TailwindCSS?</span>
        <ChevronDownIcon 
          :class="{ 'rotate-180': openItem === 1 }" 
          class="w-5 h-5 transform transition-transform" 
        />
      </button>
      <Transition name="accordion">
        <div v-show="openItem === 1" class="px-6 py-4 border-t border-gray-200 bg-gray-50">
          <p class="text-gray-700">TailwindCSS is a utility-first CSS framework...</p>
        </div>
      </Transition>
    </div>
    
    <div class="bg-white border border-gray-200 shadow-sm rounded-lg">
      <button 
        @click="toggleAccordion(2)" 
        class="w-full px-6 py-4 text-left font-semibold flex justify-between items-center hover:bg-gray-50 transition-colors">
        <span>How do I get started?</span>
        <ChevronDownIcon 
          :class="{ 'rotate-180': openItem === 2 }" 
          class="w-5 h-5 transform transition-transform" 
        />
      </button>
      <Transition name="accordion">
        <div v-show="openItem === 2" class="px-6 py-4 border-t border-gray-200 bg-gray-50">
          <p class="text-gray-700">Start by installing TailwindCSS via npm...</p>
        </div>
      </Transition>
    </div>

    <div class="bg-white border border-gray-200 shadow-sm rounded-lg">
      <button 
        @click="toggleAccordion(3)" 
        class="w-full px-6 py-4 text-left font-semibold flex justify-between items-center hover:bg-gray-50 transition-colors">
        <span>Is it responsive by default?</span>
        <ChevronDownIcon 
          :class="{ 'rotate-180': openItem === 3 }" 
          class="w-5 h-5 transform transition-transform" 
        />
      </button>
      <Transition name="accordion">
        <div v-show="openItem === 3" class="px-6 py-4 border-t border-gray-200 bg-gray-50">
          <p class="text-gray-700">Yes! TailwindCSS includes responsive variants...</p>
        </div>
      </Transition>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { ChevronDownIcon } from '@heroicons/vue/24/outline'

const openItem = ref(null)

const toggleAccordion = (item) => {
  openItem.value = openItem.value === item ? null : item
}
</script>
import React, { useState } from 'react'
import { ChevronDownIcon } from '@heroicons/react/24/outline'

const BasicAccordion = () => {
  const [openItem, setOpenItem] = useState(null)

  const toggleAccordion = (item) => {
    setOpenItem(openItem === item ? null : item)
  }

  const accordionItems = [
    {
      id: 1,
      question: "What is TailwindCSS?",
      answer: "TailwindCSS is a utility-first CSS framework that provides low-level utility classes to build custom designs directly in your markup."
    },
    {
      id: 2,
      question: "How do I get started?",
      answer: "Start by installing TailwindCSS via npm or including it via CDN. Then begin using utility classes in your HTML."
    },
    {
      id: 3,
      question: "Is it responsive by default?",
      answer: "Yes! TailwindCSS includes responsive variants for almost every utility class, making it easy to build responsive designs."
    }
  ]

  return (
    <div className="space-y-2">
      {accordionItems.map((item) => (
        <div key={item.id} className="bg-white border border-gray-200 shadow-sm rounded-lg">
          <button 
            onClick={() => toggleAccordion(item.id)}
            className="w-full px-6 py-4 text-left font-semibold flex justify-between items-center hover:bg-gray-50 transition-colors"
          >
            <span>{item.question}</span>
            <ChevronDownIcon 
              className={`w-5 h-5 transform transition-transform ${openItem === item.id ? 'rotate-180' : ''}`}
            />
          </button>
          {openItem === item.id && (
            <div className="px-6 py-4 border-t border-gray-200 bg-gray-50">
              <p className="text-gray-700">{item.answer}</p>
            </div>
          )}
        </div>
      ))}
    </div>
  )
}

export default BasicAccordion

2. Plus/Minus Accordion

Clean accordion with plus/minus icons that smoothly animate between states.

We support React, Vue, Angular, and vanilla JavaScript. All components are built with TailwindCSS for easy customization.

Absolutely! Since we use TailwindCSS, you can easily modify colors, spacing, and styling by changing the utility classes.

Yes! Each component comes with detailed documentation, code examples, and usage guidelines to help you get started quickly.

<div x-data="{ open: null }" class="space-y-3">
    <div class="border border-gray-300 rounded-lg">
        <button @click="open = open === 1 ? null : 1" class="w-full px-6 py-4 text-left font-medium flex justify-between items-center hover:bg-gray-50 transition-colors">
            <span>What frameworks do you support?</span>
            <div class="flex items-center justify-center w-6 h-6 text-gray-500">
                <svg x-show="open !== 1" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
                </svg>
                <svg x-show="open === 1" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14" />
                </svg>
            </div>
        </button>
        <div x-show="open === 1" x-collapse>
            <div class="px-6 py-4 border-t border-gray-200 text-gray-700">
                <p>We support React, Vue, Angular, and vanilla JavaScript. All components are built with TailwindCSS for easy customization.</p>
            </div>
        </div>
    </div>
</div>
<template>
  <div class="space-y-3">
    <div v-for="item in accordionItems" :key="item.id" class="border border-gray-300 rounded-lg">
      <button @click="toggleAccordion(item.id)" class="w-full px-6 py-4 text-left font-medium flex justify-between items-center hover:bg-gray-50 transition-colors">
        <span>{{ item.question }}</span>
        <div class="flex items-center justify-center w-6 h-6 text-gray-500">
          <PlusIcon v-show="openItem !== item.id" class="w-5 h-5" />
          <MinusIcon v-show="openItem === item.id" class="w-5 h-5" />
        </div>
      </button>
      <div v-show="openItem === item.id" class="px-6 py-4 border-t border-gray-200 text-gray-700">
        <p>{{ item.answer }}</p>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { PlusIcon, MinusIcon } from '@heroicons/vue/24/outline'

const openItem = ref(null)
const toggleAccordion = (itemId) => {
  openItem.value = openItem.value === itemId ? null : itemId
}

const accordionItems = [
  { id: 1, question: "What frameworks do you support?", answer: "We support React, Vue, Angular, and vanilla JavaScript." },
  { id: 2, question: "Can I customize the colors?", answer: "Absolutely! Since we use TailwindCSS, you can easily modify colors." },
  { id: 3, question: "Do you provide documentation?", answer: "Yes! Each component comes with detailed documentation." }
]
</script>
import React, { useState } from 'react'
import { PlusIcon, MinusIcon } from '@heroicons/react/24/outline'

const PlusMinusAccordion = () => {
  const [openItem, setOpenItem] = useState(null)
  
  const toggleAccordion = (itemId) => {
    setOpenItem(openItem === itemId ? null : itemId)
  }

  const accordionItems = [
    { id: 1, question: "What frameworks do you support?", answer: "We support React, Vue, Angular, and vanilla JavaScript." },
    { id: 2, question: "Can I customize the colors?", answer: "Absolutely! Since we use TailwindCSS, you can easily modify colors." },
    { id: 3, question: "Do you provide documentation?", answer: "Yes! Each component comes with detailed documentation." }
  ]

  return (
    <div className="space-y-3">
      {accordionItems.map((item) => (
        <div key={item.id} className="border border-gray-300 rounded-lg">
          <button onClick={() => toggleAccordion(item.id)} className="w-full px-6 py-4 text-left font-medium flex justify-between items-center hover:bg-gray-50 transition-colors">
            <span>{item.question}</span>
            <div className="flex items-center justify-center w-6 h-6 text-gray-500">
              {openItem !== item.id ? <PlusIcon className="w-5 h-5" /> : <MinusIcon className="w-5 h-5" />}
            </div>
          </button>
          {openItem === item.id && (
            <div className="px-6 py-4 border-t border-gray-200 text-gray-700">
              <p>{item.answer}</p>
            </div>
          )}
        </div>
      ))}
    </div>
  )
}

export default PlusMinusAccordion

3. Gradient Card Accordion

Colorful gradient cards with icons, shadow animations, and smooth slide effects.

Our components are built with performance in mind, utilizing modern CSS techniques and minimal JavaScript for maximum speed.

Change colors, spacing, and styles instantly with Tailwind's utility classes. No complex CSS required.

All components are battle-tested in real applications, with comprehensive documentation and support.

<div x-data="{ open: null }" class="space-y-4">
    <div class="bg-gradient-to-r from-blue-500 to-purple-600 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300">
        <button @click="open = open === 1 ? null : 1" class="w-full px-6 py-5 text-left flex items-center gap-4 text-white">
            <div class="flex-shrink-0 w-12 h-12 bg-white/20 rounded-lg flex items-center justify-center backdrop-blur-sm">
                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
                </svg>
            </div>
            <div class="flex-grow">
                <h3 class="font-bold text-lg">Lightning Fast Performance</h3>
                <p class="text-blue-100 text-sm">Optimized for speed and efficiency</p>
            </div>
            <div class="flex-shrink-0">
                <svg class="w-6 h-6 transform transition-transform duration-300" :class="{'rotate-180': open === 1}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
                </svg>
            </div>
        </button>
        <div x-show="open === 1" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 -translate-y-2" x-transition:enter-end="opacity-100 translate-y-0" x-transition:leave="transition ease-in duration-200" x-transition:leave-start="opacity-100 translate-y-0" x-transition:leave-end="opacity-0 -translate-y-2">
            <div class="px-6 pb-5 ml-16">
                <div class="bg-white/10 backdrop-blur-sm rounded-lg p-4 text-white">
                    <p class="leading-relaxed">Our components are built with performance in mind, utilizing modern CSS techniques and minimal JavaScript for maximum speed.</p>
                </div>
            </div>
        </div>
    </div>
</div>
<template>
  <div class="space-y-4">
    <div v-for="card in cardItems" :key="card.id" :class="card.gradient" class="rounded-xl shadow-lg hover:shadow-xl transition-all duration-300">
      <button @click="toggleAccordion(card.id)" class="w-full px-6 py-5 text-left flex items-center gap-4 text-white">
        <div class="flex-shrink-0 w-12 h-12 bg-white/20 rounded-lg flex items-center justify-center backdrop-blur-sm">
          <component :is="card.icon" class="w-6 h-6" />
        </div>
        <div class="flex-grow">
          <h3 class="font-bold text-lg">{{ card.title }}</h3>
          <p :class="card.textColor" class="text-sm">{{ card.subtitle }}</p>
        </div>
        <div class="flex-shrink-0">
          <ChevronDownIcon :class="{ 'rotate-180': openItem === card.id }" class="w-6 h-6 transform transition-transform duration-300" />
        </div>
      </button>
      <div v-show="openItem === card.id" class="px-6 pb-5 ml-16">
        <div class="bg-white/10 backdrop-blur-sm rounded-lg p-4 text-white">
          <p class="leading-relaxed">{{ card.content }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { ChevronDownIcon, BoltIcon, HeartIcon, ShieldCheckIcon } from '@heroicons/vue/24/outline'

const openItem = ref(null)
const toggleAccordion = (itemId) => {
  openItem.value = openItem.value === itemId ? null : itemId
}

const cardItems = [
  { id: 1, title: "Lightning Fast Performance", subtitle: "Optimized for speed", content: "Built with performance in mind.", icon: BoltIcon, gradient: "bg-gradient-to-r from-blue-500 to-purple-600", textColor: "text-blue-100" },
  { id: 2, title: "Easy to Customize", subtitle: "Tailwind utility classes", content: "Change colors and styles instantly.", icon: HeartIcon, gradient: "bg-gradient-to-r from-green-500 to-emerald-600", textColor: "text-green-100" },
  { id: 3, title: "Production Ready", subtitle: "Thoroughly tested", content: "Battle-tested in real applications.", icon: ShieldCheckIcon, gradient: "bg-gradient-to-r from-orange-500 to-red-500", textColor: "text-orange-100" }
]
</script>
import React, { useState } from 'react'
import { ChevronDownIcon, BoltIcon, HeartIcon, ShieldCheckIcon } from '@heroicons/react/24/outline'

const GradientCardAccordion = () => {
  const [openItem, setOpenItem] = useState(null)

  const toggleAccordion = (itemId) => {
    setOpenItem(openItem === itemId ? null : itemId)
  }

  const cardItems = [
    { id: 1, title: "Lightning Fast Performance", subtitle: "Optimized for speed", content: "Built with performance in mind.", icon: BoltIcon, gradient: "bg-gradient-to-r from-blue-500 to-purple-600", textColor: "text-blue-100" },
    { id: 2, title: "Easy to Customize", subtitle: "Tailwind utility classes", content: "Change colors and styles instantly.", icon: HeartIcon, gradient: "bg-gradient-to-r from-green-500 to-emerald-600", textColor: "text-green-100" },
    { id: 3, title: "Production Ready", subtitle: "Thoroughly tested", content: "Battle-tested in real applications.", icon: ShieldCheckIcon, gradient: "bg-gradient-to-r from-orange-500 to-red-500", textColor: "text-orange-100" }
  ]

  return (
    <div className="space-y-4">
      {cardItems.map((card) => {
        const IconComponent = card.icon
        return (
          <div key={card.id} className={`${card.gradient} rounded-xl shadow-lg hover:shadow-xl transition-all duration-300`}>
            <button onClick={() => toggleAccordion(card.id)} className="w-full px-6 py-5 text-left flex items-center gap-4 text-white">
              <div className="flex-shrink-0 w-12 h-12 bg-white/20 rounded-lg flex items-center justify-center backdrop-blur-sm">
                <IconComponent className="w-6 h-6" />
              </div>
              <div className="flex-grow">
                <h3 className="font-bold text-lg">{card.title}</h3>
                <p className={`${card.textColor} text-sm`}>{card.subtitle}</p>
              </div>
              <div className="flex-shrink-0">
                <ChevronDownIcon className={`w-6 h-6 transform transition-transform duration-300 ${openItem === card.id ? 'rotate-180' : ''}`} />
              </div>
            </button>
            {openItem === card.id && (
              <div className="px-6 pb-5 ml-16">
                <div className="bg-white/10 backdrop-blur-sm rounded-lg p-4 text-white">
                  <p className="leading-relaxed">{card.content}</p>
                </div>
              </div>
            )}
          </div>
        )
      })}
    </div>
  )
}

export default GradientCardAccordion

🚀 How to Use These Components

Requirements

  • TailwindCSS v4.0+ installed (Install Guide)
  • AlpineJS for interactivity (HTML version)
  • Heroicons for icons (optional)
    • React: npm install @heroicons/react
    • Vue: npm install @heroicons/vue

Installation

# Install TailwindCSS
# Install Heroicons for React
npm install @heroicons/react
# Install Heroicons for Vue
npm install @heroicons/vue

Pro Tip: These accordions work great for FAQs, product features, documentation, and any collapsible content. Customize colors, spacing, and animations to match your brand.

We use cookies to improve your experience and analytics. You can accept all cookies or reject non-essential ones.

Learn More