Skip to content

Accordion ​

Expand and collapse content sections to organize information efficiently. Perfect for FAQs, documentation, and grouped content. Built for Pulse Framework with multiple variants and full reactivity support.

Import ​

ts
import { Accordion, BasicAccordion, BorderedAccordion, type AccordionItem } from '@odyssee-software/components';

Basic Usage ​

Code Éditable
Résultat

Variants ​

Basic Accordion (Plus/Minus Icons) ​

The default variant with plus/minus icons.

Code Éditable
Résultat

No Arrow Accordion ​

Clean accordion without any icons.

Code Éditable
Résultat

Arrow Accordion (Chevron Icons) ​

Accordion with chevron up/down icons.

Code Éditable
Résultat

Stretched Accordion ​

Title and arrow stretched to opposite ends.

Code Éditable
Résultat

Bordered Accordion ​

Accordion with borders around each item.

Code Éditable
Résultat

Active Bordered Accordion ​

Borders appear only on active (expanded) items.

Code Éditable
Résultat

Multiple Open Items ​

Allow multiple sections to be open simultaneously.

Code Éditable
Résultat

Disabled Items ​

Prevent specific items from being opened.

Code Éditable
Résultat

Reactive State ​

Control accordion state with Pulse signals for dynamic behavior.

tsx
import { Accordion, Button, Pulse } from '@odyssee-software/components';
import type { AccordionItem } from '@odyssee-software/components';

const ReactiveAccordion = () => {
  // Create reactive items
  const items = Pulse.signal<AccordionItem[]>([
    {
      id: 'react-1',
      title: 'Section 1',
      content: 'First section content',
      open: false
    },
    {
      id: 'react-2',
      title: 'Section 2',
      content: 'Second section content',
      open: false
    },
    {
      id: 'react-3',
      title: 'Section 3',
      content: 'Third section content',
      open: false
    }
  ]);

  const openAll = () => {
    items(items().map(item => ({ ...item, open: true })));
  };

  const closeAll = () => {
    items(items().map(item => ({ ...item, open: false })));
  };

  return (
    <div>
      <div class="flex gap-2 mb-4">
        <Button onClick={openAll} size="sm">Open All</Button>
        <Button onClick={closeAll} variant="outline" size="sm">Close All</Button>
      </div>
      <Accordion items={items} multiple={true} />
    </div>
  );
};

Rich Content ​

Use custom HTML elements for more complex content.

tsx
const richItems: AccordionItem[] = [
  {
    id: 'rich-1',
    title: 'Product Features',
    content: (
      <div class="space-y-3">
        <div class="flex items-start gap-3">
          <span class="text-green-600">✓</span>
          <div>
            <h4 class="font-semibold">Fast Performance</h4>
            <p class="text-sm text-gray-600">Lightning-fast rendering and updates</p>
          </div>
        </div>
        <div class="flex items-start gap-3">
          <span class="text-green-600">✓</span>
          <div>
            <h4 class="font-semibold">Fully Responsive</h4>
            <p class="text-sm text-gray-600">Works perfectly on all devices</p>
          </div>
        </div>
        <div class="flex items-start gap-3">
          <span class="text-green-600">✓</span>
          <div>
            <h4 class="font-semibold">Easy Integration</h4>
            <p class="text-sm text-gray-600">Simple API and great documentation</p>
          </div>
        </div>
      </div>
    ),
    open: true
  }
];

<Accordion.Bordered items={richItems} />

Props ​

PropTypeDefaultDescription
itemsAccordionItem[]RequiredArray of accordion items
multiplebooleanfalseAllow multiple items open simultaneously
borderedbooleanfalseAdd borders around items
classNamestring-Additional CSS classes
idstringAuto-generatedHTML id attribute
stylestring | object-Inline styles

AccordionItem Interface ​

PropertyTypeDefaultDescription
idstringRequiredUnique identifier for the item
titlestringRequiredItem title/header text
contentstring | HTMLElementRequiredItem content body
openbooleanfalseInitial open state
disabledbooleanfalseDisable item interaction

Accessibility ​

The Accordion component follows WCAG guidelines and accessibility best practices:

  • ✅ Proper ARIA attributes (aria-expanded, aria-controls, aria-labelledby)
  • ✅ Semantic HTML structure with proper headings
  • ✅ Keyboard navigation support (Tab, Enter, Space)
  • ✅ Focus management and visible focus indicators
  • ✅ Screen reader friendly with region roles
  • ✅ Color contrast meets WCAG AA standards
tsx
// The component automatically includes:
// - aria-expanded="true/false" on buttons
// - aria-controls linking to content
// - role="region" on content areas
// - aria-labelledby linking content to headers
// - Disabled state properly communicated

const accessibleAccordion = (
  <Accordion
    items={items}
    // Accessibility features work automatically
    // No additional configuration needed
  />
);

Best Practices ​

✅ Do ​

  • Use clear, descriptive titles
  • Keep related information grouped
  • Use appropriate variants for your design
  • Consider the multiple prop for long forms
  • Provide meaningful content
tsx
// Good: Clear structure and organization
const goodAccordion = (
  <BorderedAccordion
    items={[
      {
        id: 'shipping',
        title: 'Shipping Information',
        content: 'Detailed shipping policies and timelines...'
      },
      {
        id: 'returns',
        title: 'Return Policy',
        content: 'Clear return instructions and conditions...'
      },
      {
        id: 'warranty',
        title: 'Warranty Coverage',
        content: 'Comprehensive warranty information...'
      }
    ]}
  />
);

❌ Don't ​

  • Don't nest accordions too deeply
  • Don't hide critical information by default
  • Don't use for navigation (use tabs/menu)
  • Don't create items with empty content
  • Don't use too many items (consider pagination)
tsx
// Bad: Too many items, unclear titles
const badAccordion = (
  <Accordion
    items={[
      { id: '1', title: 'Item 1', content: '...' },
      { id: '2', title: 'Item 2', content: '...' },
      // ... 50 more items
      { id: '52', title: 'Item 52', content: '...' }
    ]}
  />
);

// Better: Categorize or paginate

Use Cases ​

Product Documentation ​

tsx
const ProductDocs = () => {
  const sections: AccordionItem[] = [
    {
      id: 'install',
      title: 'Installation',
      content: 'npm install @odyssee/components',
      open: true
    },
    {
      id: 'setup',
      title: 'Initial Setup',
      content: 'Import components and configure your app...'
    },
    {
      id: 'usage',
      title: 'Basic Usage',
      content: 'Examples of common component patterns...'
    },
    {
      id: 'advanced',
      title: 'Advanced Features',
      content: 'Deep dive into advanced functionality...'
    }
  ];

  return <BorderedAccordion items={sections} />;
};

Settings Panel ​

tsx
const SettingsPanel = () => {
  const settings: AccordionItem[] = [
    {
      id: 'profile',
      title: 'Profile Settings',
      content: (
        <div class="space-y-3">
          <Input label="Display Name" />
          <Input label="Email" type="email" />
          <Button>Save Changes</Button>
        </div>
      )
    },
    {
      id: 'notifications',
      title: 'Notification Preferences',
      content: (
        <div class="space-y-2">
          <Checkbox label="Email notifications" />
          <Checkbox label="Push notifications" />
          <Checkbox label="SMS notifications" />
        </div>
      )
    },
    {
      id: 'privacy',
      title: 'Privacy & Security',
      content: (
        <div class="space-y-3">
          <Toggle label="Two-factor authentication" />
          <Toggle label="Profile visibility" />
        </div>
      )
    }
  ];

  return <Accordion items={settings} multiple={true} />;
};

Pricing Tiers ​

tsx
const PricingAccordion = () => {
  const plans: AccordionItem[] = [
    {
      id: 'basic',
      title: 'Basic Plan - $9/month',
      content: (
        <div>
          <ul class="list-disc list-inside space-y-2 mb-4">
            <li>Up to 10 projects</li>
            <li>5 GB storage</li>
            <li>Email support</li>
            <li>Basic analytics</li>
          </ul>
          <Button variant="outline" fullWidth>Choose Plan</Button>
        </div>
      )
    },
    {
      id: 'pro',
      title: 'Pro Plan - $29/month',
      content: (
        <div>
          <Badge variant="soft" color="success" className="mb-3">Most Popular</Badge>
          <ul class="list-disc list-inside space-y-2 mb-4">
            <li>Unlimited projects</li>
            <li>50 GB storage</li>
            <li>Priority support</li>
            <li>Advanced analytics</li>
            <li>Team collaboration</li>
          </ul>
          <Button color="primary" fullWidth>Choose Plan</Button>
        </div>
      )
    },
    {
      id: 'enterprise',
      title: 'Enterprise Plan - Custom',
      content: (
        <div>
          <ul class="list-disc list-inside space-y-2 mb-4">
            <li>Everything in Pro</li>
            <li>Unlimited storage</li>
            <li>Dedicated support</li>
            <li>Custom integrations</li>
            <li>SLA guarantee</li>
          </ul>
          <Button variant="outline" fullWidth>Contact Sales</Button>
        </div>
      )
    }
  ];

  return <StretchedAccordion items={plans} />;
};

Styling & Theming ​

All accordion styles use Tailwind CSS and automatically support dark mode.

Custom Styling ​

tsx
const customAccordion = (
  <Accordion
    items={items}
    className="space-y-2"
    // Each variant supports className prop
  />
);

// Customize individual items
const customItems: AccordionItem[] = [
  {
    id: 'custom',
    title: 'Custom Styled Item',
    content: (
      <div class="bg-gradient-to-r from-blue-50 to-purple-50 p-4 rounded-lg dark:from-blue-900/20 dark:to-purple-900/20">
        <p class="text-gray-800 dark:text-gray-200">Custom styled content</p>
      </div>
    )
  }
];

Dark Mode ​

tsx
// Dark mode works automatically with Tailwind's dark: classes
const darkModeAccordion = (
  <BorderedAccordion
    items={items}
    // Automatically adapts to dark mode:
    // - Text colors adjust
    // - Borders adapt
    // - Hover states change
  />
);

TypeScript ​

Full TypeScript support with complete type definitions.

tsx
import type { AccordionProps, AccordionItem } from '@odyssee-software/components';

// Type-safe item definition
const items: AccordionItem[] = [
  {
    id: 'ts-1',
    title: 'TypeScript Support',
    content: 'Full type safety and IntelliSense support',
    open: true
  },
  {
    id: 'ts-2',
    title: 'Type Definitions',
    content: 'Complete interfaces for all props and items'
  }
];

// Type-safe props
const props: AccordionProps = {
  items,
  multiple: false,
  bordered: true,
  className: 'custom-accordion'
};

const accordion = <Accordion {...props} />;

// Type checking for custom content
const typedItem: AccordionItem = {
  id: 'typed',
  title: 'Typed Content',
  content: (
    <div>Type-safe JSX content</div>
  )
};
  • Collapse - Single collapsible section
  • Tabs - Switch between content panels
  • Card - Content container with optional sections

Version: 1.0.0
Last Updated: January 2025

Released under the MIT License.