Skip to Content
Dashflow Logo

Accordion Component

A comprehensive guide to using the Accordion component with examples, props, and best practices.


Overview

The Accordion component is a collapsible content container that allows users to expand and collapse sections of content. It supports multiple variants and configurations to accommodate various design requirements.

Basic Usage

import { useState } from 'react'
import { Accordion } from '@dashflowx/core'
const items = [
{
value: 'item-1',
title: 'What is DashFlowX?',
description: 'DashFlowX is a modern React component library designed for building beautiful and accessible user interfaces.'
},
{
value: 'item-2',
title: 'How do I get started?',
description: 'You can install DashFlowX using npm or yarn and start building your application with our pre-built components.'
}
]
export default function AccordionExample() {
const [openValue, setOpenValue] = useState('item-1')
return (
<Accordion
type="single"
collapsible={true}
variant="basic"
items={items}
className="max-w-2xl mx-auto"
value={openValue}
onValueChange={setOpenValue}
/>
)
}

State Management Examples & Live Preview

This section combines both the code examples and live previews to show you how to implement accordions with proper state management and see them working in real-time.

Single Type Accordion with State

import { useState } from 'react'
import { Accordion } from '@dashflowx/core'
function SingleAccordionExample() {
const [openValue, setOpenValue] = useState('item-1')
const handleValueChange = (value: string) => {
setOpenValue(value)
console.log('Accordion opened:', value)
}
const items = [
{
value: 'item-1',
title: 'What is DashFlowX?',
description: 'DashFlowX is a modern React component library designed for building beautiful and accessible user interfaces. It provides a comprehensive set of pre-built components that follow modern design principles and accessibility standards.'
},
{
value: 'item-2',
title: 'How do I get started?',
description: 'You can install DashFlowX using npm or yarn and start building your application with our pre-built components. The library includes TypeScript support and extensive documentation to help you get up and running quickly.'
},
{
value: 'item-3',
title: 'What features does it include?',
description: 'DashFlowX includes responsive design, dark mode support, accessibility features, and a flexible theming system. All components are built with performance and developer experience in mind.'
}
]
return (
<div className="max-w-2xl mx-auto">
<div className="mb-4 p-4 bg-blue-50 rounded-lg">
<p className="text-sm text-blue-800">
<strong>Current open item:</strong> {openValue}
</p>
</div>
<Accordion
type="single"
collapsible={true}
variant="basic"
items={items}
value={openValue}
onValueChange={handleValueChange}
className="space-y-2"
/>
</div>
)
}

Live Preview:

Multiple Type Accordion with State

import { useState } from 'react'
import { Accordion } from '@dashflowx/core'
function MultipleAccordionExample() {
const [openValues, setOpenValues] = useState(['item-1'])
const handleValueChange = (values: string[]) => {
setOpenValues(values)
console.log('Open items:', values)
}
const items = [
{
value: 'item-1',
title: 'Installation Guide',
description: 'Learn how to install DashFlowX in your project using npm, yarn, or pnpm. We provide step-by-step instructions for different project setups.'
},
{
value: 'item-2',
title: 'Getting Started',
description: 'Follow our quick start guide to create your first component and understand the basic concepts of DashFlowX.'
},
{
value: 'item-3',
title: 'Component Examples',
description: 'Explore our comprehensive collection of component examples with different variants, sizes, and configurations.'
}
]
return (
<div className="max-w-2xl mx-auto">
<div className="mb-4 p-4 bg-green-50 rounded-lg">
<p className="text-sm text-green-800">
<strong>Open items:</strong> {openValues.join(', ') || 'None'}
</p>
<p className="text-sm text-green-700 mt-1">
<strong>Total open:</strong> {openValues.length}
</p>
</div>
<Accordion
type="multiple"
collapsible={true}
variant="basic"
items={items}
value={openValues}
onValueChange={handleValueChange}
className="space-y-2"
/>
</div>
)
}

Live Preview:

Advanced State Management with Custom Logic

import { useState, useEffect } from 'react'
import { Accordion } from '@dashflowx/core'
function AdvancedAccordionExample() {
const [openValue, setOpenValue] = useState('item-1')
const [lastOpened, setLastOpened] = useState<string | null>(null)
const [openCount, setOpenCount] = useState(0)
const handleValueChange = (value: string) => {
const previousValue = openValue
setOpenValue(value)
setLastOpened(previousValue)
setOpenCount(prev => prev + 1)
// Custom analytics tracking
if (typeof window !== 'undefined' && window.gtag) {
window.gtag('event', 'accordion_item_open', {
item_value: value,
previous_value: previousValue,
open_count: openCount + 1
})
}
// Custom business logic
if (value === 'installation') {
console.log('User opened installation guide - showing related content')
}
}
const items = [
{
value: 'installation',
title: 'Installation Guide',
description: 'Complete installation guide with step-by-step instructions for different environments and package managers.'
},
{
value: 'configuration',
title: 'Configuration',
description: 'Learn how to configure DashFlowX for your project, including theming, plugins, and custom settings.'
},
{
value: 'examples',
title: 'Examples & Demos',
description: 'Explore real-world examples and interactive demos to see DashFlowX components in action.'
}
]
return (
<div className="max-w-2xl mx-auto">
<div className="mb-4 p-4 bg-purple-50 rounded-lg">
<div className="grid grid-cols-2 gap-4 text-sm">
<div>
<p className="text-purple-800 font-medium">Current Open:</p>
<p className="text-purple-700">{openValue}</p>
</div>
<div>
<p className="text-purple-800 font-medium">Last Opened:</p>
<p className="text-purple-700">{lastOpened || 'None'}</p>
</div>
<div>
<p className="text-purple-800 font-medium">Total Opens:</p>
<p className="text-purple-700">{openCount}</p>
</div>
<div>
<p className="text-purple-800 font-medium">Status:</p>
<p className="text-purple-700">{openValue ? 'Active' : 'Closed'}</p>
</div>
</div>
</div>
<Accordion
type="single"
collapsible={true}
variant="basic"
items={items}
value={openValue}
onValueChange={handleValueChange}
className="space-y-2"
/>
</div>
)
}

Live Preview:

Props

PropTypeDefaultDescription
variant'basic' | 'one'-The visual style variant of the accordion
type'single' | 'multiple''single'Whether only one or multiple items can be open
collapsiblebooleantrueWhether items can be collapsed when clicked again
itemsArray<iDfxAccordionItems>-Array of accordion items
defaultValuestring-The default open item value
valuestring-Controlled value for the open item
onValueChange(value: string) => void-Callback when the open item changes
disabledbooleanfalseWhether the entire accordion is disabled
classNamestring-Additional CSS classes for the accordion container
itemClassNamestring-Additional CSS classes for each accordion item
itemTriggerClassNamestring-Additional CSS classes for each accordion trigger
itemContentClassNamestring-Additional CSS classes for each accordion content
onClick(event: React.MouseEvent) => void-Callback when accordion container is clicked

Item Interface

interface iDfxAccordionItems {
value: string; // Unique identifier for the item
title: string | JSX.Element; // The title/trigger content
description: string | JSX.Element; // The content to display when expanded
disabled?: boolean; // Whether this specific item is disabled
}

State Management Best Practices

Controlled vs Uncontrolled

// ✅ Controlled (recommended for most cases)
const [openValue, setOpenValue] = useState('item-1')
<Accordion
value={openValue}
onValueChange={setOpenValue}
// ... other props
/>
// ✅ Uncontrolled (simple cases)
<Accordion
defaultValue="item-1"
// ... other props
/>

State Persistence

import { useState, useEffect } from 'react'
function PersistentAccordion() {
const [openValue, setOpenValue] = useState(() => {
// Load from localStorage on mount
if (typeof window !== 'undefined') {
return localStorage.getItem('accordion-open') || 'item-1'
}
return 'item-1'
})
useEffect(() => {
// Save to localStorage on change
localStorage.setItem('accordion-open', openValue)
}, [openValue])
return (
<Accordion
value={openValue}
onValueChange={setOpenValue}
// ... other props
/>
)
}

Complex State Logic

function ComplexAccordion() {
const [state, setState] = useState({
openValue: 'item-1',
lastOpened: null,
openCount: 0,
userPreferences: {}
})
const handleValueChange = (value: string) => {
setState(prev => ({
...prev,
openValue: value,
lastOpened: prev.openValue,
openCount: prev.openCount + 1
}))
// Additional side effects
trackAnalytics(value)
updateUserPreferences(value)
}
return (
<Accordion
value={state.openValue}
onValueChange={handleValueChange}
// ... other props
/>
)
}

Best Practices

Accessibility Best Practices

1. Semantic HTML Structure

// ✅ Good: Use proper ARIA attributes
<Accordion
type="single"
aria-label="FAQ Section"
aria-describedby="faq-description"
// ... other props
/>
// ✅ Good: Provide descriptive labels
const items = [
{
value: 'installation',
title: 'Installation Guide',
description: 'Step-by-step installation instructions for DashFlowX'
}
]

2. Keyboard Navigation

// ✅ Good: Ensure keyboard accessibility
function AccessibleAccordion() {
const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault()
// Handle accordion toggle
}
}
return (
<Accordion
onKeyDown={handleKeyDown}
// ... other props
/>
)
}

3. Screen Reader Support

// ✅ Good: Provide context for screen readers
<div>
<h2 id="accordion-heading">Frequently Asked Questions</h2>
<p id="accordion-description">
Expand each section to learn more about DashFlowX
</p>
<Accordion
aria-labelledby="accordion-heading"
aria-describedby="accordion-description"
// ... other props
/>
</div>

Performance Best Practices

1. Memoization for Expensive Content

import { useMemo } from 'react'
function OptimizedAccordion() {
const expensiveContent = useMemo(() => {
// Expensive computation or rendering
return <ComplexComponent data={largeDataset} />
}, [largeDataset])
const items = [
{
value: 'complex',
title: 'Complex Content',
description: expensiveContent
}
]
return <Accordion items={items} />
}

2. Lazy Loading Content

import { lazy, Suspense } from 'react'
const LazyComponent = lazy(() => import('./HeavyComponent'))
function LazyAccordion() {
const items = [
{
value: 'lazy',
title: 'Heavy Component',
description: (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
)
}
]
return <Accordion items={items} />
}

3. Debounced State Updates

import { useCallback } from 'react'
import { debounce } from 'lodash'
function DebouncedAccordion() {
const debouncedValueChange = useCallback(
debounce((value: string) => {
// Expensive operation (API call, analytics, etc.)
trackUserBehavior(value)
}, 300),
[]
)
return (
<Accordion
onValueChange={debouncedValueChange}
// ... other props
/>
)
}

Design Best Practices

1. Consistent Spacing and Typography

// ✅ Good: Use consistent design tokens
const accordionStyles = {
container: 'max-w-4xl mx-auto space-y-6',
item: 'border border-gray-200 rounded-lg overflow-hidden',
trigger: 'px-6 py-4 text-left font-medium text-gray-900 hover:bg-gray-50',
content: 'px-6 py-4 bg-gray-50 text-gray-700'
}
<Accordion
className={accordionStyles.container}
itemClassName={accordionStyles.item}
itemTriggerClassName={accordionStyles.trigger}
itemContentClassName={accordionStyles.content}
// ... other props
/>

2. Visual Feedback and States

// ✅ Good: Provide clear visual feedback
const getItemStyles = (isOpen: boolean, isDisabled: boolean) => {
if (isDisabled) return 'opacity-50 cursor-not-allowed'
if (isOpen) return 'bg-blue-50 border-blue-200'
return 'hover:bg-gray-50 transition-colors duration-200'
}
<Accordion
itemClassName={getItemStyles(isOpen, isDisabled)}
// ... other props
/>

3. Responsive Design

// ✅ Good: Ensure mobile-friendly design
function ResponsiveAccordion() {
const isMobile = useMediaQuery('(max-width: 768px)')
return (
<Accordion
className={isMobile ? 'space-y-2' : 'space-y-4'}
itemTriggerClassName={isMobile ? 'px-4 py-3' : 'px-6 py-4'}
// ... other props
/>
)
}

Implementation Best Practices

1. Error Boundaries

import { ErrorBoundary } from 'react-error-boundary'
function ErrorFallback({ error }: { error: Error }) {
return (
<div className="p-4 bg-red-50 border border-red-200 rounded-lg">
<p className="text-red-800">Something went wrong: {error.message}</p>
</div>
)
}
function SafeAccordion() {
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<Accordion
// ... props
/>
</ErrorBoundary>
)
}

2. Type Safety

// ✅ Good: Use strict typing
interface AccordionItem {
value: string
title: string
description: string
disabled?: boolean
metadata?: Record<string, unknown>
}
interface AccordionProps {
items: AccordionItem[]
type: 'single' | 'multiple'
value?: string | string[]
onValueChange?: (value: string | string[]) => void
}
function TypedAccordion({ items, type, value, onValueChange }: AccordionProps) {
return (
<Accordion
items={items}
type={type}
value={value}
onValueChange={onValueChange}
/>
)
}

3. Testing Best Practices

// ✅ Good: Test accordion behavior
import { render, screen, fireEvent } from '@testing-library/react'
test('accordion toggles correctly', () => {
render(<AccordionExample />)
const trigger = screen.getByText('What is DashFlowX?')
fireEvent.click(trigger)
expect(screen.getByText('DashFlowX is a modern React component library')).toBeVisible()
})
test('single type closes other items', () => {
render(<SingleTypeAccordion />)
const firstItem = screen.getByText('Item 1')
const secondItem = screen.getByText('Item 2')
fireEvent.click(firstItem)
fireEvent.click(secondItem)
// First item should be closed when second is opened
expect(screen.queryByText('Content 1')).not.toBeVisible()
})

Content Organization Best Practices

1. Logical Grouping

// ✅ Good: Group related items logically
const faqItems = [
{
value: 'getting-started',
title: 'Getting Started',
description: 'Basic setup and installation'
},
{
value: 'installation',
title: 'Installation',
description: 'Detailed installation steps'
},
{
value: 'configuration',
title: 'Configuration',
description: 'Setting up your project'
}
]
const advancedItems = [
{
value: 'customization',
title: 'Customization',
description: 'Advanced customization options'
},
{
value: 'performance',
title: 'Performance',
description: 'Optimization techniques'
}
]

2. Progressive Disclosure

// ✅ Good: Use accordions for progressive disclosure
function ProgressiveAccordion() {
const [userLevel, setUserLevel] = useState<'beginner' | 'intermediate' | 'advanced'>('beginner')
const getItemsForLevel = (level: string) => {
switch (level) {
case 'beginner':
return basicItems
case 'intermediate':
return [...basicItems, ...intermediateItems]
case 'advanced':
return [...basicItems, ...intermediateItems, ...advancedItems]
default:
return basicItems
}
}
return (
<div>
<select value={userLevel} onChange={(e) => setUserLevel(e.target.value as any)}>
<option value="beginner">Beginner</option>
<option value="intermediate">Intermediate</option>
<option value="advanced">Advanced</option>
</select>
<Accordion
items={getItemsForLevel(userLevel)}
// ... other props
/>
</div>
)
}

3. Content Validation

// ✅ Good: Validate accordion content
function validateAccordionItems(items: AccordionItem[]): boolean {
return items.every(item => {
if (!item.value || !item.title || !item.description) {
console.error('Invalid accordion item:', item)
return false
}
if (item.value.length < 3) {
console.warn('Short accordion value:', item.value)
}
return true
})
}
function ValidatedAccordion({ items }: { items: AccordionItem[] }) {
useEffect(() => {
if (!validateAccordionItems(items)) {
console.error('Invalid accordion items detected')
}
}, [items])
return <Accordion items={items} />
}

SEO and Analytics Best Practices

1. Structured Data

// ✅ Good: Add structured data for SEO
function SEOAccordion() {
const structuredData = {
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": items.map(item => ({
"@type": "Question",
"name": item.title,
"acceptedAnswer": {
"@type": "Answer",
"text": item.description
}
}))
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
/>
<Accordion items={items} />
</>
)
}

2. Analytics Tracking

// ✅ Good: Track user interactions
function AnalyticsAccordion() {
const trackAccordionOpen = (itemValue: string, itemTitle: string) => {
// Google Analytics
if (typeof window !== 'undefined' && window.gtag) {
window.gtag('event', 'accordion_open', {
event_category: 'User Interaction',
event_label: itemTitle,
value: itemValue
})
}
// Custom analytics
analytics.track('accordion_item_opened', {
item: itemValue,
title: itemTitle,
timestamp: Date.now()
})
}
return (
<Accordion
onValueChange={trackAccordionOpen}
// ... other props
/>
)
}

These best practices ensure your accordion components are accessible, performant, maintainable, and provide an excellent user experience across all devices and use cases.

Edit this page on GitHub