logo
CtrlK
ComponentsTemplates

Components

Accordion
Alert
Avatar
Badge
Banner
Bottom Navigation
Breadcrumb
Button
Call to Action
Card
Date Picker
Divider
Dropdown
Featues
File Upload
Footer
Header
Hero
Loader
Pagination
Popover
Sidebar
Skeleton
Social Share
Tabs
Testimonial
Tooltip

Pages

Error Pages
Blog List
  1. Docs
  2. Components
  3. Accordion

Accordion

Accordion component is used to show and hide content with a toggle button.

Basic Accordion

import React, { useState, useRef, useEffect } from "react";

const AnimatedArrow: React.FC<{ isExpanded: boolean }> = ({ isExpanded }) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    className={`h-5 w-5 transform transition-transform duration-500 ease-out text-gray-400 dark:text-gray-500 ${
      isExpanded ? "rotate-180" : ""
    }`}
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
  >
    <path
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="1.5"
      d="M19 9l-7 7-7-7"
    />
  </svg>
);

const Accordion: React.FC = () => {
  const [isExpanded, setIsExpanded] = useState(false);
  const [height, setHeight] = useState<number | undefined>(0);
  const contentRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (isExpanded) {
      const contentEl = contentRef.current;
      setHeight(contentEl?.scrollHeight);
    } else {
      setHeight(0);
    }
  }, [isExpanded]);

  const toggleAccordion = () => {
    setIsExpanded(!isExpanded);
  };

  return (
    <div className="max-w-lg mx-auto sm:max-w-sm lg:max-w-3xl my-4">
      <div className="rounded-xl overflow-hidden bg-white dark:bg-gray-900 shadow-sm">
        <div
          className="flex items-center justify-between cursor-pointer py-4 px-6 transition-colors duration-200 hover:bg-gray-50 dark:hover:bg-gray-800"
          onClick={toggleAccordion}
        >
          <div className="text-base font-medium text-gray-900 dark:text-gray-100">
            Accordion Title
          </div>
          <span className="ml-6 flex items-center">
            <AnimatedArrow isExpanded={isExpanded} />
          </span>
        </div>
        <div
          className="transition-all duration-500 ease-out overflow-hidden bg-gray-50 dark:bg-gray-800"
          style={{ height }}
        >
          <div ref={contentRef} className="px-6 py-4">
            <p className="text-sm leading-relaxed text-gray-600 dark:text-gray-300">
              Accordion content goes here...
            </p>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Accordion;

Bordered Accordion

import React, { useState, useRef, useEffect } from "react";

const AnimatedArrow: React.FC<{ isExpanded: boolean }> = ({ isExpanded }) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    className={`h-5 w-5 transform transition-transform duration-500 ease-out text-gray-400 dark:text-gray-500 ${
      isExpanded ? "rotate-180" : ""
    }`}
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
  >
    <path
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="1.5"
      d="M19 9l-7 7-7-7"
    />
  </svg>
);
const Accordion: React.FC = () => {
  const [isExpanded, setIsExpanded] = useState(false);
  const [height, setHeight] = useState<number | undefined>(0);
  const contentRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (isExpanded) {
      const contentEl = contentRef.current;
      setHeight(contentEl?.scrollHeight);
    } else {
      setHeight(0);
    }
  }, [isExpanded]);

  const toggleAccordion = () => {
    setIsExpanded(!isExpanded);
  };

  return (
    <div className="max-w-lg mx-auto sm:max-w-sm lg:max-w-3xl my-4">
      <div className="border border-gray-200 dark:border-gray-700 rounded-xl overflow-hidden backdrop-blur-sm bg-white/50 dark:bg-gray-900/50">
        <div
          className={`flex items-center justify-between cursor-pointer py-4 px-6 transition-colors duration-200 
            hover:bg-gray-50 dark:hover:bg-gray-800/50
            ${
              isExpanded ? "border-b border-gray-200 dark:border-gray-700" : ""
            }`}
          onClick={toggleAccordion}
        >
          <div className="text-base font-medium text-gray-900 dark:text-gray-100">
            Accordion Title
          </div>
          <span className="ml-6 flex items-center">
            <AnimatedArrow isExpanded={isExpanded} />
          </span>
        </div>
        <div
          className="transition-all duration-500 ease-out overflow-hidden"
          style={{ height }}
        >
          <div ref={contentRef} className="px-6 py-4">
            <p className="text-sm leading-relaxed text-gray-600 dark:text-gray-300">
              Accordion content goes here...
            </p>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Accordion;

Alert

On this page

Basic AccordionBordered Accordion
logo

Empowering developers with intuitive and efficient UI components.

Created by Abhay Singh Rathore, a passionate Full-Stack Developer & UI/UX designer.

Quick Links

  • Home
  • Components
  • Templates

Connect

© 2025 Business Wish. All rights reserved.