
Syncfusion React Accordion
- 299 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
Use syncfusion-react-accordion for development tasks
About
syncfusion-react-accordion: A skill for development. This provides functionality for development workflows.
- syncfusion-react-accordion
Syncfusion React Accordion by the numbers
- 299 all-time installs (skills.sh)
- +22 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,329 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-accordionAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 299 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
What it does
Use syncfusion-react-accordion for development tasks
Files
Implementing Syncfusion React Accordion
The React Accordion component provides a clean, organized way to display content in collapsible panels. It's perfect for creating expandable content sections, FAQs, multi-step forms, and navigation menus with minimal code.
Component Overview
The Accordion component renders a stack of collapsible panels where:
- Each panel has a header (clickable to toggle) and content area
- Headers can be simple text or custom templates
- Content can be static, dynamic, or rendered from other React components
- Supports single expand mode (one panel at a time) or multiple (many panels at once)
- Built-in animations for smooth expand/collapse transitions
- Full keyboard navigation and accessibility support
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
When to read: First time setting up the Accordion component
- Package installation (@syncfusion/ej2-react-navigations)
- CSS imports and theme configuration (Tailwind, Bootstrap)
- Two initialization methods (Items API vs HTML markup)
- Item configuration (header, content, cssClass, disabled, expanded)
- Basic component setup with examples
- First render and minimal working example
Expand Modes
📄 Read: references/expand-modes.md
When to read: Controlling which panels expand at the same time
- Single expand mode (only one panel open at a time)
- Multiple expand mode (default, many panels can be open)
- Setting initial expanded state with
expandedIndicesproperty - Toggle behavior on header click
- Use cases for choosing each mode
- Keeping single pane open always pattern
Animation Effects
📄 Read: references/animation-effects.md
When to read: Customizing panel transitions and visual effects
- Default animations (SlideDown for expand, SlideUp for collapse)
- Choosing from available animation effects (FadeIn, ZoomIn, etc.)
- Configuring easing and duration properties
- Separate expand/collapse animation control
- Disabling animations entirely
- Performance considerations
Content Loading
📄 Read: references/content-loading.md
When to read: Loading content dynamically or from external sources
- Loading accordion items dynamically with
addItem()method - Loading content from data sources (dataSource property)
- Fetching content via HTTP requests and POST
- Template-based rendering (headerTemplate, itemTemplate)
- Rendering other React components inside panels
- Lazy loading and deferred content patterns
Events & Lifecycle
📄 Read: references/events-lifecycle.md
When to read: Handling user interactions and component lifecycle
- Component lifecycle events (created, destroyed)
- Expand/collapse events (expanding, expanded)
- Click event handling (clicked)
- Event arguments and properties
- Preventing default actions with event.cancel
- Real-world event patterns and examples
Styling & Customization
📄 Read: references/styling-customization.md
When to read: Customizing appearance and integrating with design systems
- CSS classes for styling (header, panel, content areas)
- Built-in theme options and theme switching
- Custom styling with CSS and utilities (Tailwind, Bootstrap)
- RTL (right-to-left) support
- Responsive design patterns
- Using cssClass property for custom styling
Advanced Features
📄 Read: references/advanced-features.md
When to read: Building complex layouts and optimizing performance
- Component methods (expandItem, enableItem, hideItem, etc.)
- Nested accordions and hierarchical structures
- React hooks integration (useState, useRef, useEffect)
- Keyboard navigation behavior
- Accessibility features (ARIA attributes, screen readers)
- Performance optimization for large accordion lists
- Custom expand/collapse action patterns
---
Quick Start Example
Basic accordion with three collapsible panels:
import React from 'react';
import { AccordionComponent, AccordionItemDirective, AccordionItemsDirective } from '@syncfusion/ej2-react-navigations';
import '@syncfusion/ej2-base/styles/tailwind3.css';
import '@syncfusion/ej2-buttons/styles/tailwind3.css';
import '@syncfusion/ej2-popups/styles/tailwind3.css';
import '@syncfusion/ej2-react-navigations/styles/tailwind3.css';
export default function App() {
return (
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective
header='HTML'
content='HTML is a markup language used to create web pages.'
/>
<AccordionItemDirective
header='CSS'
content='CSS is used to style HTML elements and create layouts.'
/>
<AccordionItemDirective
header='JavaScript'
content='JavaScript adds interactivity to web applications.'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Common Patterns
Pattern 1: FAQ Section (Single Expand Mode)
Questions automatically collapse when a new one is opened:
<AccordionComponent expandMode='Single'>
<AccordionItemsDirective>
<AccordionItemDirective header='What is React?' content='React is a JavaScript library for building UIs with components.' />
<AccordionItemDirective header='What is JSX?' content='JSX is a syntax extension for writing HTML-like code in JavaScript.' />
</AccordionItemsDirective>
</AccordionComponent>Pattern 2: Persistent Expansion (Multiple Mode)
All panels can remain expanded simultaneously:
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective expanded={true} header='Features' content='...' />
<AccordionItemDirective expanded={true} header='Installation' content='...' />
</AccordionItemsDirective>
</AccordionComponent>Pattern 3: Default Expanded State
Pre-expand specific panels on load:
<AccordionItemDirective
expanded={true}
header='Quick Start'
content='This section opens by default.'
/>---
Key Props & Methods
Component Properties
| Property | Type | Purpose | Default |
|---|---|---|---|
expandMode | 'Single' \ | 'Multiple' | Control single/multiple panel expansion |
expandedIndices | number[] | Array of indices for initially expanded items | [] |
animation | AnimationSettings | Expand/collapse animation config | SlideDown/SlideUp |
dataSource | Object[] | Array of items for data binding | [] |
headerTemplate | string \ | function | Custom header template for all items |
itemTemplate | string \ | function | Custom item template for rendering |
height | string \ | number | Component height in px/% |
width | string \ | number | Component width in px/% |
enableHtmlSanitizer | boolean | Sanitize untrusted HTML content | true |
enablePersistence | boolean | Persist expanded state between reloads | false |
enableRtl | boolean | Enable right-to-left layout | false |
locale | string | Locale code for internationalization | '' |
Item Properties
| Property | Type | Purpose | Default |
|---|---|---|---|
header | string | Item header text (accepts HTML) | - |
content | string | Item content text (accepts HTML) | - |
expanded | boolean | Set initial expanded state for item | false |
disabled | boolean | Disable specific accordion item | false |
cssClass | string | Custom CSS classes for item | - |
Component Methods
| Method | Parameters | Purpose |
|---|---|---|
addItem() | item, index (optional) | Add new accordion item(s) |
removeItem() | index | Remove item at specified index |
enableItem() | index, isEnable | Enable/disable specific item |
hideItem() | index, isHidden | Show/hide specific item |
expandItem() | isExpand, index (optional) | Expand/collapse items |
select() | index | Set focus to item header |
destroy() | none | Remove component from DOM |
---
Common Use Cases
| Use Case | Mode | Key Feature |
|---|---|---|
| FAQ Section | Single | Only one question visible at a time |
| Settings Panel | Multiple | Check multiple options simultaneously |
| Multi-Step Form | Single | Guide user through steps sequentially |
| Content Organizer | Multiple | Browse multiple topics at once |
| Navigation Menu | Single | Tree-like hierarchical navigation |
| Data Dashboard | Multiple | View multiple data sections together |
---
Next Steps
1. Start with Getting Started to set up your first Accordion 2. Choose Expand Mode based on your use case 3. Add Animations for polish and user feedback 4. Load Content Dynamically if using data sources 5. Customize Styling to match your design system 6. Explore Advanced Features for complex scenarios
Need help? Check the specific reference files above based on what you're trying to build!
Advanced Features
Table of Contents
- Nested Accordions
- Events and Lifecycle
- React Hooks Integration
- Keyboard Navigation
- Accessibility Features
- Performance Optimization
- Advanced Patterns
Component Methods
Programmatically control the accordion using component methods.
Methods Reference
| Method | Parameters | Return | Description |
|---|---|---|---|
addItem(item, index) | item: AccordionItem, index?: number | void | Add a new item to the accordion |
removeItem(index) | index: number | void | Remove item at specified index |
enableItem(index, enable) | index: number, enable: boolean | void | Enable or disable an item |
hideItem(index, hide) | index: number, hide: boolean | void | Hide or show an item |
expandItem(expand, index) | expand: boolean, index: number | void | Expand or collapse specific item |
select(index) | index: number | void | Select/expand item at index |
destroy() | - | void | Destroy the component |
Adding Items Dynamically
Use addItem() to insert new accordion items at runtime:
import React, { useRef, useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const accordionRef = useRef(null);
const [itemCount, setItemCount] = useState(2);
const addNewItem = () => {
const newIndex = itemCount;
const newItem = {
header: `Item ${newIndex + 1}`,
content: `Content for item ${newIndex + 1}`
};
accordionRef.current?.addItem(newItem, newIndex);
setItemCount(newIndex + 1);
};
return (
<div>
<button onClick={addNewItem}>Add New Item</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Removing Items
Use removeItem() to delete accordion items:
import React, { useRef } from 'react';
export default function App() {
const accordionRef = useRef(null);
const removeLastItem = () => {
const accordion = accordionRef.current;
if (accordion && accordion.items.length > 0) {
const lastIndex = accordion.items.length - 1;
accordion.removeItem(lastIndex);
}
};
const removeItemAt = (index) => {
accordionRef.current?.removeItem(index);
};
return (
<div>
<button onClick={removeLastItem}>Remove Last Item</button>
<button onClick={() => removeItemAt(0)}>Remove First Item</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Enabling/Disabling Items
Use enableItem() to toggle item interactivity:
import React, { useRef, useState } from 'react';
export default function App() {
const accordionRef = useRef(null);
const [disabledItems, setDisabledItems] = useState(new Set());
const toggleItemState = (index) => {
const accordion = accordionRef.current;
const isCurrentlyDisabled = disabledItems.has(index);
accordion?.enableItem(index, isCurrentlyDisabled);
const newDisabled = new Set(disabledItems);
if (isCurrentlyDisabled) {
newDisabled.delete(index);
} else {
newDisabled.add(index);
}
setDisabledItems(newDisabled);
};
return (
<div>
<p>Disabled items: {Array.from(disabledItems).join(', ') || 'None'}</p>
<button onClick={() => toggleItemState(0)}>Toggle Item 1</button>
<button onClick={() => toggleItemState(1)}>Toggle Item 2</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Hiding/Showing Items
Use hideItem() to toggle item visibility:
import React, { useRef, useState } from 'react';
export default function App() {
const accordionRef = useRef(null);
const [visibleItems, setVisibleItems] = useState(
new Set([0, 1, 2]) // All items initially visible
);
const toggleItemVisibility = (index) => {
const accordion = accordionRef.current;
const isCurrentlyVisible = visibleItems.has(index);
accordion?.hideItem(index, isCurrentlyVisible);
const newVisible = new Set(visibleItems);
if (isCurrentlyVisible) {
newVisible.delete(index);
} else {
newVisible.add(index);
}
setVisibleItems(newVisible);
};
const showAllItems = () => {
for (let i = 0; i < 3; i++) {
accordionRef.current?.hideItem(i, false);
}
setVisibleItems(new Set([0, 1, 2]));
};
return (
<div>
<button onClick={showAllItems}>Show All Items</button>
<button onClick={() => toggleItemVisibility(0)}>Toggle Item 1</button>
<button onClick={() => toggleItemVisibility(1)}>Toggle Item 2</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Expanding/Collapsing Items
Use expandItem() to programmatically control expand state:
import React, { useRef } from 'react';
export default function App() {
const accordionRef = useRef(null);
const expandAll = () => {
const accordion = accordionRef.current;
if (accordion) {
for (let i = 0; i < accordion.items.length; i++) {
accordion.expandItem(true, i);
}
}
};
const collapseAll = () => {
const accordion = accordionRef.current;
if (accordion) {
for (let i = 0; i < accordion.items.length; i++) {
accordion.expandItem(false, i);
}
}
};
const toggleItemExpand = (index) => {
const accordion = accordionRef.current;
if (accordion) {
// Get current state and toggle
const header = accordion.element.querySelectorAll('.e-accordion-header')[index];
const isExpanded = header?.classList.contains('e-selected');
accordion.expandItem(!isExpanded, index);
}
};
return (
<div>
<button onClick={expandAll}>Expand All</button>
<button onClick={collapseAll}>Collapse All</button>
<button onClick={() => toggleItemExpand(0)}>Toggle Item 1</button>
<AccordionComponent ref={accordionRef} expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Selecting Items
Use select() method as a shorthand to expand an item:
import React, { useRef } from 'react';
export default function App() {
const accordionRef = useRef(null);
const selectItem = (index) => {
accordionRef.current?.select(index);
};
return (
<div>
<button onClick={() => selectItem(0)}>Select Item 1</button>
<button onClick={() => selectItem(1)}>Select Item 2</button>
<button onClick={() => selectItem(2)}>Select Item 3</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Destroying Components
Use destroy() to clean up the accordion:
import React, { useRef } from 'react';
export default function App() {
const accordionRef = useRef(null);
const destroyAccordion = () => {
accordionRef.current?.destroy();
console.log('Accordion destroyed');
};
return (
<div>
<button onClick={destroyAccordion}>Destroy Accordion</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Complete Example: Dynamic Item Management
import React, { useRef, useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const accordionRef = useRef(null);
const [items, setItems] = useState([
{ id: 1, header: 'Item 1', content: 'Content 1' },
{ id: 2, header: 'Item 2', content: 'Content 2' }
]);
const addItem = () => {
const newId = Math.max(...items.map(i => i.id), 0) + 1;
const newItem = {
id: newId,
header: `Item ${newId}`,
content: `Content ${newId}`
};
setItems([...items, newItem]);
accordionRef.current?.addItem(newItem);
};
const removeItem = (index) => {
accordionRef.current?.removeItem(index);
setItems(items.filter((_, i) => i !== index));
};
const expandAllItems = () => {
for (let i = 0; i < items.length; i++) {
accordionRef.current?.expandItem(true, i);
}
};
const collapseAllItems = () => {
for (let i = 0; i < items.length; i++) {
accordionRef.current?.expandItem(false, i);
}
};
return (
<div>
<div style={{ marginBottom: '20px', display: 'flex', gap: '10px' }}>
<button onClick={addItem}>Add Item</button>
<button onClick={expandAllItems}>Expand All</button>
<button onClick={collapseAllItems}>Collapse All</button>
</div>
<AccordionComponent ref={accordionRef} expandMode='Multiple'>
<AccordionItemsDirective>
{items.map((item, index) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={() => (
<div>
{item.content}
<button onClick={() => removeItem(index)}>Remove</button>
</div>
)}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Nested Accordions
Create hierarchical accordion structures with nested panels:
Basic Nested Accordion
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
function NestedAccordionContent() {
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
header='Nested Item 1'
content='Nested content 1'
/>
<AccordionItemDirective
header='Nested Item 2'
content='Nested content 2'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}
export default function App() {
return (
<AccordionComponent expandMode='Single'>
<AccordionItemsDirective>
<AccordionItemDirective
header='Parent 1'
content={() => <NestedAccordionContent />}
/>
<AccordionItemDirective
header='Parent 2'
content='Simple content'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Multi-Level Nesting
function Level3Accordion() {
return (
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective header='Level 3-A' content='Deep content A' />
<AccordionItemDirective header='Level 3-B' content='Deep content B' />
</AccordionItemsDirective>
</AccordionComponent>
);
}
function Level2Accordion() {
return (
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective
header='Level 2-A'
content={() => <Level3Accordion />}
/>
<AccordionItemDirective
header='Level 2-B'
content='Content 2-B'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}
export default function App() {
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
header='Level 1'
content={() => <Level2Accordion />}
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Styling Nested Accordions
/* Parent accordion styling */
.e-accordion {
background: white;
border-radius: 8px;
}
/* Nested accordion styling (one level deeper) */
.e-accordion .e-accordion-content .e-accordion {
border: 1px solid #e0e0e0;
border-radius: 4px;
margin-top: 10px;
}
/* Third level nesting */
.e-accordion .e-accordion-content .e-accordion .e-accordion-content .e-accordion {
border: 1px solid #f0f0f0;
background: #fafafa;
}Events and Lifecycle
Handle accordion interactions using event callbacks:
Available Events
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [eventLog, setEventLog] = useState([]);
const onExpand = (args) => {
console.log('Panel expanding:', args);
setEventLog(prev => [...prev, `Expanding item ${args.index}`]);
};
const onExpanded = (args) => {
console.log('Panel expanded:', args);
setEventLog(prev => [...prev, `Expanded item ${args.index}`]);
};
const onCollapse = (args) => {
console.log('Panel collapsing:', args);
setEventLog(prev => [...prev, `Collapsing item ${args.index}`]);
};
const onCollapsed = (args) => {
console.log('Panel collapsed:', args);
setEventLog(prev => [...prev, `Collapsed item ${args.index}`]);
};
return (
<div>
<AccordionComponent
expanding={onExpand}
expanded={onExpanded}
collapsing={onCollapse}
collapsed={onCollapsed}
>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
</AccordionItemsDirective>
</AccordionComponent>
<div style={{ marginTop: '20px', padding: '10px', backgroundColor: '#f5f5f5' }}>
<h4>Event Log:</h4>
{eventLog.map((event, index) => (
<div key={index}>{event}</div>
))}
</div>
</div>
);
}Event Properties
Each event receives an args object with:
{
index: number, // Index of accordion item (0-based)
item: HTMLElement, // DOM element of accordion item
content: HTMLElement, // Content element
header: HTMLElement, // Header element
isInteracted: boolean, // Whether user interacted or programmatic
name: string // Event name
}Preventing Expand/Collapse
const onExpanding = (args) => {
if (/* some condition */) {
args.cancel = true; // Prevent expand
}
};
<AccordionComponent expanding={onExpanding}>
{/* items */}
</AccordionComponent>React Hooks Integration
Use React hooks to manage accordion state:
useState for Controlled State
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [expandedItems, setExpandedItems] = useState([0]); // Item 0 expanded
const handleExpanded = (args) => {
setExpandedItems(prev =>
prev.includes(args.index) ? prev : [...prev, args.index]
);
};
const handleCollapsed = (args) => {
setExpandedItems(prev => prev.filter(i => i !== args.index));
};
return (
<div>
<p>Expanded items: {expandedItems.join(', ')}</p>
<AccordionComponent
expanded={handleExpanded}
collapsed={handleCollapsed}
>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={expandedItems.includes(0)}
header='Item 1'
content='Content 1'
/>
<AccordionItemDirective
expanded={expandedItems.includes(1)}
header='Item 2'
content='Content 2'
/>
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}useRef for Direct Component Access
import React, { useRef } from 'react';
import { AccordionComponent, AccordionItemDirective, AccordionItemsDirective } from '@syncfusion/ej2-react-navigations';
export default function App() {
const accordionRef = useRef(null);
const expandAll = () => {
const accordion = accordionRef.current;
// Expand all items programmatically
for (let i = 0; i < accordion.items.length; i++) {
accordion.expandItem(true, i);
}
};
const collapseAll = () => {
const accordion = accordionRef.current;
for (let i = 0; i < accordion.items.length; i++) {
accordion.collapseItem(i);
}
};
return (
<div>
<button onClick={expandAll}>Expand All</button>
<button onClick={collapseAll}>Collapse All</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}useEffect for Side Effects
import React, { useState, useEffect, useRef } from 'react';
export default function App() {
const [itemCount, setItemCount] = useState(3);
const accordionRef = useRef(null);
useEffect(() => {
console.log(`Item count changed to ${itemCount}`);
// Perform cleanup or updates when itemCount changes
}, [itemCount]);
useEffect(() => {
// Expand first item on mount
if (accordionRef.current) {
accordionRef.current.expandItem(true, 0);
}
}, []);
return (
<div>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
{/* Generate items based on itemCount */}
{Array.from({ length: itemCount }).map((_, i) => (
<AccordionItemDirective
key={i}
header={`Item ${i + 1}`}
content={`Content ${i + 1}`}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Keyboard Navigation
The Accordion supports full keyboard navigation by default:
Navigation Keys
| Key | Action |
|---|---|
Space / Enter | Expand/collapse focused header |
Down Arrow | Move focus to next header |
Up Arrow | Move focus to previous header |
Home | Move focus to first header |
End | Move focus to last header |
Tab | Move to next focusable element |
Shift + Tab | Move to previous focusable element |
Enable/Disable Keyboard Navigation
Keyboard navigation is enabled by default. To programmatically control focus:
import React, { useRef } from 'react';
export default function App() {
const accordionRef = useRef(null);
const focusHeader = (index) => {
if (accordionRef.current) {
const header = accordionRef.current.element
.querySelectorAll('.e-accordion-header')[index];
if (header) {
header.focus();
}
}
};
return (
<div>
<button onClick={() => focusHeader(0)}>Focus Item 1</button>
<button onClick={() => focusHeader(1)}>Focus Item 2</button>
<AccordionComponent ref={accordionRef}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Accessibility Features
The Accordion is fully accessible with built-in ARIA support:
ARIA Attributes
| Attribute | Purpose | Value |
|---|---|---|
role="button" | Header role | Indicates clickable element |
aria-expanded | Expand state | true or false |
aria-controls | Content control | Points to content panel ID |
aria-labelledby | Content label | Points to header ID |
aria-hidden | Content visibility | true (collapsed) or false (expanded) |
These are automatically set by the component.
Screen Reader Example
// With proper ARIA attributes, screen readers announce:
// "Item 1 button, collapsed, press Space to expand"
// On expand:
// "Item 1 button, expanded, press Space to collapse"
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
header='Frequently Asked Questions'
content='Common questions and answers'
/>
</AccordionItemsDirective>
</AccordionComponent>Testing Accessibility
// Test with accessibility tools
import { axe, toHaveNoViolations } from 'jest-axe';
test('Accordion has no accessibility violations', async () => {
const { container } = render(
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective header='Item' content='Content' />
</AccordionItemsDirective>
</AccordionComponent>
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});Performance Optimization
Virtualization for Large Lists
For 100+ items, use virtualization:
import React, { useState, useEffect } from 'react';
import { FixedSizeList } from 'react-window';
export default function App() {
const [items, setItems] = useState([]);
useEffect(() => {
// Generate 1000 items
const largeDataset = Array.from({ length: 1000 }, (_, i) => ({
id: i,
header: `Item ${i + 1}`,
content: `Content for item ${i + 1}`
}));
setItems(largeDataset);
}, []);
const Row = ({ index, style }) => (
<div style={style}>
<div className='e-accordion-item'>
<div className='e-accordion-header'>
{items[index].header}
</div>
<div className='e-accordion-content'>
{items[index].content}
</div>
</div>
</div>
);
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width='100%'
>
{Row}
</FixedSizeList>
);
}Pagination Instead of Virtual Scroll
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 10;
const allItems = Array.from({ length: 500 }, (_, i) => ({
id: i,
header: `Item ${i + 1}`,
content: `Content ${i + 1}`
}));
const startIdx = (currentPage - 1) * itemsPerPage;
const paginatedItems = allItems.slice(startIdx, startIdx + itemsPerPage);
return (
<div>
<AccordionComponent>
<AccordionItemsDirective>
{paginatedItems.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
<div style={{ marginTop: '20px' }}>
<button
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
disabled={currentPage === 1}
>
Previous
</button>
<span> Page {currentPage} </span>
<button
onClick={() => setCurrentPage(p => p + 1)}
disabled={startIdx + itemsPerPage >= allItems.length}
>
Next
</button>
</div>
</div>
);
}Memoization for Performance
import React, { memo, useState } from 'react';
// Memoized item component
const AccordionItem = memo(({ header, content }) => (
<AccordionItemDirective header={header} content={content} />
));
export default function App() {
const [items] = useState(Array.from({ length: 100 }, (_, i) => ({
header: `Item ${i + 1}`,
content: `Content ${i + 1}`
})));
return (
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item, index) => (
<AccordionItem
key={index}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Advanced Patterns
Pattern 1: Synchronized Accordions
Multiple accordions that expand/collapse together:
import React, { useState } from 'react';
export default function App() {
const [expandedIndex, setExpandedIndex] = useState(0);
return (
<div>
<h3>Accordion 1</h3>
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={expandedIndex === 0}
header='Item 1-A'
content='...'
/>
<AccordionItemDirective
expanded={expandedIndex === 1}
header='Item 1-B'
content='...'
/>
</AccordionItemsDirective>
</AccordionComponent>
<h3>Accordion 2</h3>
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={expandedIndex === 0}
header='Item 2-A'
content='...'
/>
<AccordionItemDirective
expanded={expandedIndex === 1}
header='Item 2-B'
content='...'
/>
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Pattern 2: Search/Filter within Accordion
import React, { useState, useMemo } from 'react';
export default function App() {
const [searchTerm, setSearchTerm] = useState('');
const allItems = [
{ id: 1, header: 'React Basics', content: 'Learn React...' },
{ id: 2, header: 'React Hooks', content: 'Master Hooks...' },
{ id: 3, header: 'React Router', content: 'Navigation...' }
];
const filteredItems = useMemo(() => {
return allItems.filter(item =>
item.header.toLowerCase().includes(searchTerm.toLowerCase())
);
}, [searchTerm]);
return (
<div>
<input
placeholder='Search accordion items...'
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<AccordionComponent>
<AccordionItemsDirective>
{filteredItems.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
{filteredItems.length === 0 && <p>No items found</p>}
</div>
);
}---
Troubleshooting
Issue: Events not firing
- Verify event handler is attached correctly
- Check event name (expanded vs expanding)
- Ensure handler function accepts args parameter
Issue: useRef not working
- Verify ref is attached to component with
ref={accordionRef} - Check that ref.current exists before accessing
- Ensure component is fully rendered
Issue: Performance degrading with many items
- Implement pagination or virtualization
- Use React.memo() to prevent unnecessary re-renders
- Check DevTools Performance tab for bottlenecks
Issue: Accessibility features not working
- Verify keyboard navigation is not disabled
- Test with screen readers (NVDA, JAWS, VoiceOver)
- Check ARIA attributes in DevTools
Animation Effects
Table of Contents
- Overview
- Default Animations
- Available Animation Effects
- Configuring Animation Properties
- Custom Expand/Collapse Animations
- Disabling Animations
- Performance Considerations
- Common Patterns
Overview
The Accordion component provides smooth animations when panels expand and collapse. By default, panels use SlideDown for expand and SlideUp for collapse animations. You can customize animations with various effects, durations, and easing functions.
Animation configuration includes:
- Effect - Type of animation (SlideDown, FadeIn, ZoomIn, etc.)
- Duration - How long animation runs in milliseconds
- Easing - Animation timing function (ease-in, ease-out, etc.)
Default Animations
By default, the Accordion uses predefined animations for smooth expand/collapse:
Default Configuration
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective header='Section 1' content='This uses default animations' />
<AccordionItemDirective header='Section 2' content='SlideDown on expand, SlideUp on collapse' />
</AccordionItemsDirective>
</AccordionComponent>
);
}Default Behavior:
- Expand: SlideDown animation
- Collapse: SlideUp animation
- Duration: 400ms
- Easing: ease-out
These defaults provide natural, smooth transitions without additional configuration.
Available Animation Effects
The Accordion supports multiple animation effects for both expand and collapse actions:
Effect Types
| Effect | Description | Best For |
|---|---|---|
SlideDown | Panel slides down smoothly | Default, natural expand |
SlideUp | Panel slides up smoothly | Default, natural collapse |
FadeIn | Panel fades in gradually | Subtle, minimalist UI |
FadeOut | Panel fades out gradually | Subtle, minimalist UI |
FadeZoomIn | Panel fades while growing | Modern, engaging |
FadeZoomOut | Panel fades while shrinking | Modern, engaging |
ZoomIn | Panel grows from center | Eye-catching expand |
ZoomOut | Panel shrinks to center | Eye-catching collapse |
None | No animation | Fast interaction |
Choosing Effects
For professional/minimal UI:
expand: { effect: 'FadeIn', duration: 300 }
collapse: { effect: 'FadeOut', duration: 300 }For modern/engaging UI:
expand: { effect: 'FadeZoomIn', duration: 400 }
collapse: { effect: 'FadeZoomOut', duration: 400 }For fast/responsive UI:
expand: { effect: 'None' }
collapse: { effect: 'None' }Configuring Animation Properties
Basic Animation Configuration
Set animation properties on the Accordion component:
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const animationSettings = {
expand: { effect: 'SlideDown', duration: 500 },
collapse: { effect: 'SlideUp', duration: 500 }
};
return (
<AccordionComponent animation={animationSettings}>
<AccordionItemsDirective>
<AccordionItemDirective header='Custom Animation' content='Slides at 500ms' />
<AccordionItemDirective header='Another Item' content='Same animation effect' />
</AccordionItemsDirective>
</AccordionComponent>
);
}Animation Properties
Each animation object accepts:
{
effect: 'SlideDown' | 'FadeIn' | 'ZoomIn' | 'None', // Animation type
duration: 400, // Milliseconds
easing: 'ease-out' // CSS easing function
}Custom Expand/Collapse Animations
Set different animations for expand and collapse actions:
Expand and Collapse with Different Effects
const customAnimation = {
expand: {
effect: 'FadeZoomIn',
duration: 400,
easing: 'ease-out'
},
collapse: {
effect: 'FadeZoomOut',
duration: 300,
easing: 'ease-in'
}
};
<AccordionComponent animation={customAnimation}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item' content='Different expand/collapse animations' />
</AccordionItemsDirective>
</AccordionComponent>Behavior:
- Expanding uses FadeZoomIn (400ms, ease-out)
- Collapsing uses FadeZoomOut (300ms, ease-in)
- Creates asymmetric animation experience
Interactive Animation Selection
Change animations based on user preferences:
import React, { useState, useRef } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
export default function App() {
const accordionRef = useRef(null);
const [expandEffect, setExpandEffect] = useState('SlideDown');
const [collapseEffect, setCollapseEffect] = useState('SlideUp');
const effectOptions = ['SlideDown', 'SlideUp', 'FadeIn', 'FadeOut', 'ZoomIn', 'ZoomOut', 'None'];
const handleExpandChange = (e) => {
if (accordionRef.current) {
accordionRef.current.animation.expand = { effect: e.value };
setExpandEffect(e.value);
}
};
const handleCollapseChange = (e) => {
if (accordionRef.current) {
accordionRef.current.animation.collapse = { effect: e.value };
setCollapseEffect(e.value);
}
};
return (
<div>
<div style={{ marginBottom: '20px' }}>
<label>Expand Animation: </label>
<DropDownListComponent
dataSource={effectOptions}
value={expandEffect}
change={handleExpandChange}
/>
</div>
<div style={{ marginBottom: '20px' }}>
<label>Collapse Animation: </label>
<DropDownListComponent
dataSource={effectOptions}
value={collapseEffect}
change={handleCollapseChange}
/>
</div>
<AccordionComponent ref={accordionRef} animation={{
expand: { effect: expandEffect },
collapse: { effect: collapseEffect }
}}>
<AccordionItemsDirective>
<AccordionItemDirective header='Try it' content='Expand/collapse animations change above' />
<AccordionItemDirective header='Test effects' content='Select different effects to see them in action' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Disabling Animations
For performance-critical scenarios or minimal UI, disable animations entirely:
Disable All Animations
const noAnimation = {
expand: { effect: 'None' },
collapse: { effect: 'None' }
};
<AccordionComponent animation={noAnimation}>
<AccordionItemsDirective>
<AccordionItemDirective header='Instant Expand' content='No animation overhead' />
</AccordionItemsDirective>
</AccordionComponent>Result: Panels expand/collapse instantly without visual transition
Disable via CSS
Alternatively, override animations with CSS:
.e-accordion .e-expand {
animation: none !important;
}
.e-accordion .e-collapse {
animation: none !important;
}Performance Considerations
Animation Duration Impact
- Shorter durations (100-300ms) - Snappier feel, better for frequent interactions
- Standard duration (300-500ms) - Good balance for most UIs
- Longer durations (500ms+) - Smooth, premium feel, may feel slow
Effect Complexity
Performant animations:
{ effect: 'SlideDown', duration: 300 } // Hardware-accelerated
{ effect: 'FadeIn', duration: 300 } // Simple opacityComplex animations (use sparingly):
{ effect: 'FadeZoomIn', duration: 800 } // Combined effects
{ effect: 'ZoomIn', duration: 800 } // Scale transformationBest Practices
1. Keep durations under 500ms for responsive feel 2. Match animations to content load - Don't animate while loading 3. Consider mobile devices - Disable animations on low-end devices 4. Test on various hardware - Smooth on desktop may lag on mobile 5. Use `None` for large lists - Many animated items can impact performance
Mobile-Friendly Pattern
const isSlowDevice = () => {
// Simple device detection
return navigator.deviceMemory < 4;
};
const animationSettings = isSlowDevice()
? { expand: { effect: 'None' }, collapse: { effect: 'None' } }
: { expand: { effect: 'SlideDown', duration: 300 }, collapse: { effect: 'SlideUp', duration: 300 } };
<AccordionComponent animation={animationSettings}>
{/* accordion items */}
</AccordionComponent>Common Patterns
Pattern 1: Professional/Minimal UI
Subtle animations for business applications:
const minimalAnimation = {
expand: { effect: 'FadeIn', duration: 250, easing: 'ease-out' },
collapse: { effect: 'FadeOut', duration: 250, easing: 'ease-in' }
};Pattern 2: Modern/Engaging UI
Pronounced animations for contemporary applications:
const modernAnimation = {
expand: { effect: 'FadeZoomIn', duration: 400, easing: 'ease-out' },
collapse: { effect: 'FadeZoomOut', duration: 400, easing: 'ease-in' }
};Pattern 3: Fast/Responsive UI
Quick animations for fast-paced interactions:
const fastAnimation = {
expand: { effect: 'SlideDown', duration: 150, easing: 'ease-out' },
collapse: { effect: 'SlideUp', duration: 150, easing: 'ease-in' }
};Pattern 4: No Animation (Accessible/Performance)
Instant expand/collapse for accessibility and performance:
const noAnimation = {
expand: { effect: 'None' },
collapse: { effect: 'None' }
};---
Troubleshooting
Issue: Animations not working
- Verify CSS imports are included (animation requires base styles)
- Check that
animationprop is properly formatted - Ensure effect names match exactly (case-sensitive)
Issue: Animations are stuttering/laggy
- Reduce animation duration (try 200-300ms)
- Use simpler effects like 'FadeIn' instead of 'FadeZoomIn'
- Check browser DevTools performance tab
- Test on different devices/browsers
Issue: Animation property changes not applying
- Use
refto access accordion instance directly - Update
animationprop on component - Force re-render if needed
Issue: Animations disabled but still animating
- Verify effect is set to 'None', not disabled
- Check for CSS overrides forcing animations
- Clear browser cache to reload styles
Issue: Duration not changing
- Ensure duration is in milliseconds (not seconds)
- Verify prop update triggers component refresh
- Check that animation object is being passed correctly
Content Loading
Table of Contents
- Overview
- Loading Content from Functions
- Loading from Data Source
- Loading via HTTP Requests
- Template-Based Rendering
- Rendering Other React Components
- Dynamic Item Loading
- Lazy Loading Patterns
Overview
The Accordion component supports multiple ways to load and render content:
1. Static Content - Hardcoded strings or functions 2. Data Source - Arrays of objects mapped to accordion items 3. HTTP Requests - Fetch content from APIs 4. JSX Templates - Render React components inside panels 5. Dynamic Loading - Add/remove items at runtime
Choose the method based on your content source and update patterns.
Loading Content from Functions
Content can be provided as JavaScript functions that return JSX or strings:
Basic Function Content
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const htmlContent = () => (
<div>
<p>HTML (HyperText Markup Language) is the standard markup language for creating web pages.</p>
<p>It provides the structure and semantics for web content.</p>
</div>
);
const cssContent = () => (
<div>
<p>CSS (Cascading Style Sheets) is used to style and layout web pages.</p>
<p>It handles colors, fonts, spacing, and responsive design.</p>
</div>
);
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective header='HTML' content={htmlContent} />
<AccordionItemDirective header='CSS' content={cssContent} />
</AccordionItemsDirective>
</AccordionComponent>
);
}Content with State
Functions can access component state:
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [userName, setUserName] = useState('John');
const [userEmail, setUserEmail] = useState('john@example.com');
const profileContent = () => (
<div>
<p><strong>Name:</strong> {userName}</p>
<p><strong>Email:</strong> {userEmail}</p>
<input
placeholder='Enter new name'
onChange={(e) => setUserName(e.target.value)}
/>
</div>
);
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective header='User Profile' content={profileContent} />
</AccordionItemsDirective>
</AccordionComponent>
);
}DataSource Binding
The dataSource property binds array data directly to the accordion, automatically generating items from data objects.
Basic DataSource Binding
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const faqData = [
{
header: 'What is React?',
content: 'React is a JavaScript library for building user interfaces...'
},
{
header: 'What are Props?',
content: 'Props are arguments passed into React components...'
},
{
header: 'What is State?',
content: 'State is similar to props, but it is private and controlled...'
}
];
return (
<AccordionComponent dataSource={faqData}>
<AccordionItemsDirective>
{faqData.map((item, index) => (
<AccordionItemDirective
key={index}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Advanced DataSource with Custom Fields
const courseData = [
{
id: 1,
courseTitle: 'React Basics',
courseSummary: 'Learn the fundamentals of React...',
instructor: 'John Doe',
duration: '4 weeks',
level: 'Beginner'
},
{
id: 2,
courseTitle: 'React Advanced',
courseSummary: 'Master advanced React patterns...',
instructor: 'Jane Smith',
duration: '6 weeks',
level: 'Advanced'
}
];
export default function App() {
return (
<AccordionComponent dataSource={courseData}>
<AccordionItemsDirective>
{courseData.map((course) => (
<AccordionItemDirective
key={course.id}
header={course.courseTitle}
content={() => (
<div>
<p>{course.courseSummary}</p>
<p><strong>Instructor:</strong> {course.instructor}</p>
<p><strong>Duration:</strong> {course.duration}</p>
<p><strong>Level:</strong> {course.level}</p>
</div>
)}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Filtering DataSource
import React, { useState, useMemo } from 'react';
export default function App() {
const [searchTerm, setSearchTerm] = useState('');
const allProducts = [
{ name: 'React Book', category: 'JavaScript' },
{ name: 'Vue Guide', category: 'JavaScript' },
{ name: 'CSS Mastery', category: 'Styling' }
];
const filteredData = useMemo(() => {
return allProducts.filter(item =>
item.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}, [searchTerm]);
return (
<div>
<input
placeholder='Search products...'
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
style={{ marginBottom: '15px', padding: '8px', width: '200px' }}
/>
<AccordionComponent dataSource={filteredData}>
<AccordionItemsDirective>
{filteredData.map((product, index) => (
<AccordionItemDirective
key={index}
header={product.name}
content={product.category}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Grouping DataSource
const data = [
{ group: 'Frontend', name: 'React', description: 'JavaScript library' },
{ group: 'Frontend', name: 'Vue', description: 'Progressive framework' },
{ group: 'Backend', name: 'Node.js', description: 'JavaScript runtime' },
{ group: 'Backend', name: 'Django', description: 'Python framework' }
];
export default function App() {
const groupedByCategory = data.reduce((acc, item) => {
if (!acc[item.group]) {
acc[item.group] = [];
}
acc[item.group].push(item);
return acc;
}, {});
return (
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
{Object.entries(groupedByCategory).map(([group, items]) => (
<AccordionItemDirective
key={group}
header={group}
content={() => (
<ul>
{items.map((item, idx) => (
<li key={idx}>
<strong>{item.name}</strong> - {item.description}
</li>
))}
</ul>
)}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Loading from Data Source
Use arrays of objects to generate accordion items dynamically:
Array-Based Loading
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const accordionData = [
{ header: 'HTML Basics', content: 'HTML provides the structure for web pages...' },
{ header: 'CSS Styling', content: 'CSS is used for visual styling and layouts...' },
{ header: 'JavaScript', content: 'JavaScript adds interactivity and dynamic behavior...' }
];
return (
<AccordionComponent>
<AccordionItemsDirective>
{accordionData.map((item, index) => (
<AccordionItemDirective
key={index}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}With Rich Objects
const courseData = [
{
id: 1,
title: 'React Fundamentals',
description: 'Learn React basics...',
duration: '4 weeks',
level: 'Beginner'
},
{
id: 2,
title: 'React Advanced',
description: 'Master React patterns...',
duration: '6 weeks',
level: 'Advanced'
}
];
const courseContent = (item) => (
<div>
<p><strong>Duration:</strong> {item.duration}</p>
<p><strong>Level:</strong> {item.level}</p>
<p>{item.description}</p>
</div>
);
<AccordionComponent>
<AccordionItemsDirective>
{courseData.map((course) => (
<AccordionItemDirective
key={course.id}
header={course.title}
content={() => courseContent(course)}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>Loading via HTTP Requests
Fetch content from APIs and render in accordion panels:
Basic API Loading
import React, { useState, useEffect } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts?_limit=5')
.then((res) => res.json())
.then((data) => {
setPosts(data);
setLoading(false);
})
.catch((error) => {
console.error('Error loading posts:', error);
setLoading(false);
});
}, []);
if (loading) return <div>Loading posts...</div>;
return (
<AccordionComponent>
<AccordionItemsDirective>
{posts.map((post) => (
<AccordionItemDirective
key={post.id}
header={post.title}
content={() => <div>{post.body}</div>}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}With Loading State
import React, { useState, useEffect } from 'react';
export default function App() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const loadData = async () => {
try {
setLoading(true);
const response = await fetch('/api/accordion-items');
if (!response.ok) throw new Error('Failed to load');
const data = await response.json();
setItems(data);
setError(null);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
loadData();
}, []);
if (loading) return <p>Loading items...</p>;
if (error) return <p>Error: {error}</p>;
return (
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.name}
content={() => <div>{item.details}</div>}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Loading via HTTP POST Requests
Send data to a server and load responses in accordion panels:
Basic POST Request
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const loadContentViaPost = async () => {
setLoading(true);
try {
const response = await fetch('/api/accordion/content', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
requestType: 'accordion-items',
format: 'json'
})
});
const data = await response.json();
setItems(data.items);
} catch (error) {
console.error('Error loading content:', error);
} finally {
setLoading(false);
}
};
return (
<div>
<button onClick={loadContentViaPost} disabled={loading}>
{loading ? 'Loading...' : 'Load Content'}
</button>
{items.length > 0 && (
<AccordionComponent style={{ marginTop: '15px' }}>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
)}
</div>
);
}POST with Form Data
import React, { useState, useRef } from 'react';
export default function App() {
const [items, setItems] = useState([]);
const formRef = useRef(null);
const submitForm = async (e) => {
e.preventDefault();
const formData = new FormData(formRef.current);
try {
const response = await fetch('/api/accordion/load', {
method: 'POST',
body: formData
});
const data = await response.json();
setItems(data.items);
} catch (error) {
console.error('Error:', error);
}
};
return (
<div>
<form ref={formRef} onSubmit={submitForm}>
<input
type='text'
name='category'
placeholder='Enter category'
required
/>
<input
type='text'
name='search'
placeholder='Search term'
/>
<button type='submit'>Search & Load</button>
</form>
{items.length > 0 && (
<AccordionComponent style={{ marginTop: '15px' }}>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
)}
</div>
);
}POST with Authentication
import React, { useState, useEffect } from 'react';
export default function App() {
const [items, setItems] = useState([]);
const [token, setToken] = useState(null);
useEffect(() => {
const loadSecureContent = async () => {
if (!token) return;
try {
const response = await fetch('/api/secured/accordion', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
userId: 123,
dataType: 'accordion'
})
});
if (response.status === 401) {
console.log('Unauthorized - token expired');
setToken(null);
return;
}
const data = await response.json();
setItems(data.items);
} catch (error) {
console.error('Error loading secure content:', error);
}
};
loadSecureContent();
}, [token]);
const login = async () => {
// Mock login
const authToken = 'eyJhbGc...(JWT token)';
setToken(authToken);
};
if (!token) {
return <button onClick={login}>Login</button>;
}
return (
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}POST on Item Expansion
Load content via POST only when item is expanded:
import React, { useState } from 'react';
import { ExpandedEventArgs } from '@syncfusion/ej2-navigations';
export default function App() {
const [contentCache, setContentCache] = useState({});
const [loading, setLoading] = useState({});
const loadContentOnExpand = async (args: ExpandedEventArgs) => {
if (args.isExpanded && !contentCache[args.index]) {
setLoading(prev => ({ ...prev, [args.index]: true }));
try {
const response = await fetch('/api/content/load', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ itemIndex: args.index })
});
const data = await response.json();
setContentCache(prev => ({
...prev,
[args.index]: data.content
}));
} catch (error) {
console.error('Error loading content:', error);
} finally {
setLoading(prev => ({ ...prev, [args.index]: false }));
}
}
};
const items = [
{ header: 'Item 1', index: 0 },
{ header: 'Item 2', index: 1 },
{ header: 'Item 3', index: 2 }
];
return (
<AccordionComponent expanded={loadContentOnExpand}>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.index}
header={item.header}
content={() => (
<>
{loading[item.index] && <p>Loading...</p>}
{contentCache[item.index] && <p>{contentCache[item.index]}</p>}
</>
)}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Handling POST Errors
import React, { useState } from 'react';
export default function App() {
const [items, setItems] = useState([]);
const [error, setError] = useState(null);
const [retryCount, setRetryCount] = useState(0);
const MAX_RETRIES = 3;
const loadWithRetry = async () => {
setError(null);
try {
const response = await fetch('/api/accordion', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ requestId: Date.now() })
});
if (!response.ok) {
if (response.status === 429) {
throw new Error('Too many requests - Please try again later');
} else if (response.status === 500) {
throw new Error('Server error - Please try again');
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
}
const data = await response.json();
setItems(data.items);
setRetryCount(0);
} catch (error) {
setError(error.message);
// Auto-retry on network errors
if (retryCount < MAX_RETRIES) {
setTimeout(() => {
setRetryCount(prev => prev + 1);
loadWithRetry();
}, 2000 * (retryCount + 1)); // Exponential backoff
}
}
};
return (
<div>
<button onClick={loadWithRetry}>Load Content</button>
{error && (
<div style={{ color: 'red', marginTop: '10px' }}>
Error: {error}
{retryCount > 0 && <p>Retry attempt {retryCount}...</p>}
</div>
)}
{items.length > 0 && (
<AccordionComponent style={{ marginTop: '15px' }}>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
)}
</div>
);
}Template-Based Rendering
Use JSX templates for complex content layouts:
Custom Template Content
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const productContent = () => (
<div style={{ padding: '15px' }}>
<div style={{ display: 'flex', gap: '15px' }}>
<img
src='/product-image.jpg'
alt='Product'
style={{ width: '100px', height: '100px' }}
/>
<div>
<h4>Product Name</h4>
<p>Price: $99.99</p>
<p>In Stock: Yes</p>
<button>Add to Cart</button>
</div>
</div>
</div>
);
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
header='Featured Product'
content={productContent}
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Dynamic Template with Data
const items = [
{ id: 1, title: 'Item 1', price: 10, inStock: true },
{ id: 2, title: 'Item 2', price: 20, inStock: false }
];
const itemTemplate = (item) => (
<div style={{ padding: '15px', borderTop: '1px solid #ddd' }}>
<h4>{item.title}</h4>
<p>Price: ${item.price}</p>
<p>Status: {item.inStock ? '✓ In Stock' : '✗ Out of Stock'}</p>
</div>
);
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.title}
content={() => itemTemplate(item)}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>Rendering Other React Components
Nest other React components inside accordion panels:
Basic Component Nesting
import React, { useState } from 'react';
import { AccordionComponent } from '@syncfusion/ej2-react-navigations';
import { TextBoxComponent } from '@syncfusion/ej2-react-inputs';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
function UserForm() {
const [name, setName] = useState('');
return (
<div style={{ padding: '15px' }}>
<TextBoxComponent
placeholder='Enter name'
value={name}
input={(e) => setName(e.value)}
/>
<ButtonComponent style={{ marginTop: '10px' }}>
Save
</ButtonComponent>
</div>
);
}
export default function App() {
return (
<AccordionComponent>
<div>
<div><div>User Information</div></div>
<div><div><UserForm /></div></div>
</div>
</AccordionComponent>
);
}Multiple Syncfusion Components
import { DatePickerComponent } from '@syncfusion/ej2-react-calendars';
import { DropDownListComponent } from '@syncfusion/ej2-react-dropdowns';
import { CheckBoxComponent } from '@syncfusion/ej2-react-buttons';
function AdvancedSettings() {
return (
<div style={{ padding: '15px' }}>
<div style={{ marginBottom: '15px' }}>
<label>Select Date:</label>
<DatePickerComponent />
</div>
<div style={{ marginBottom: '15px' }}>
<label>Choose Option:</label>
<DropDownListComponent dataSource={['Option 1', 'Option 2']} />
</div>
<div>
<CheckBoxComponent label='Enable notifications' />
</div>
</div>
);
}
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
header='Settings'
content={() => <AdvancedSettings />}
/>
</AccordionItemsDirective>
</AccordionComponent>Dynamic Item Loading
Add or remove accordion items at runtime:
Adding Items
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [items, setItems] = useState([
{ id: 1, header: 'Item 1', content: 'Content 1' },
{ id: 2, header: 'Item 2', content: 'Content 2' }
]);
const addItem = () => {
const newId = Math.max(...items.map(i => i.id)) + 1;
setItems([
...items,
{ id: newId, header: `Item ${newId}`, content: `Content ${newId}` }
]);
};
return (
<div>
<button onClick={addItem} style={{ marginBottom: '15px' }}>
Add Item
</button>
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={item.content}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Removing Items
const removeItem = (id) => {
setItems(items.filter(item => item.id !== id));
};
const removeContent = (item) => (
<div>
<p>{item.content}</p>
<button onClick={() => removeItem(item.id)}>Remove</button>
</div>
);
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.header}
content={() => removeContent(item)}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>Lazy Loading Patterns
Load content only when panels expand:
Lazy Load on Expand
import React, { useState } from 'react';
export default function App() {
const [contentCache, setContentCache] = useState({});
const loadContent = async (id) => {
if (contentCache[id]) return contentCache[id];
const response = await fetch(`/api/content/${id}`);
const data = await response.text();
setContentCache(prev => ({ ...prev, [id]: data }));
return data;
};
const handleExpand = async (id) => {
await loadContent(id);
};
const content = (item) => (
<div>
{contentCache[item.id] ? (
<p>{contentCache[item.id]}</p>
) : (
<p>Loading...</p>
)}
</div>
);
return (
<AccordionComponent onExpand={(e) => handleExpand(e.index)}>
<AccordionItemsDirective>
{/* accordion items */}
</AccordionItemsDirective>
</AccordionComponent>
);
}Progressive Loading
import React, { useState, useEffect } from 'react';
const loadItemsInBatches = async (page = 1) => {
const response = await fetch(`/api/items?page=${page}`);
return response.json();
};
export default function App() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
useEffect(() => {
const loadMore = async () => {
const newItems = await loadItemsInBatches(page);
setItems(prev => [...prev, ...newItems]);
};
loadMore();
}, [page]);
return (
<div>
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
header={item.name}
content={item.description}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
<button onClick={() => setPage(page + 1)}>Load More</button>
</div>
);
}---
Troubleshooting
Issue: Content not displaying
- Ensure
contentprop is provided for each item - Check that content functions return valid JSX or strings
- Verify data is loaded before rendering
Issue: HTTP content not loading
- Check network tab in browser DevTools
- Verify API endpoint is correct and accessible
- Add error handling for failed requests
- Check CORS settings if fetching from different domain
Issue: Components not re-rendering with new content
- Ensure state updates trigger component re-render
- Use
keyprop in mapped accordion items - Check for missing dependencies in useEffect
Issue: Performance degradation with many items
- Implement lazy loading for large datasets
- Use virtualization libraries for 100+ items
- Consider pagination instead of loading all items
Events and Lifecycle
Table of Contents
- Overview
- Component Lifecycle
- Expand/Collapse Events
- Click Events
- Event Arguments Reference
- Real-World Event Patterns
- Preventing Default Actions
Overview
The Accordion component provides comprehensive event handling for tracking user interactions and component lifecycle. You can respond to expand/collapse actions, clicks, and initialization events using event callbacks.
Component Lifecycle
Created Event
Fires once the component rendering is completed.
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const onCreated = () => {
console.log('Accordion component has been created and rendered');
// Initialize external dependencies, set up observers, etc.
};
return (
<AccordionComponent created={onCreated}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
</AccordionItemsDirective>
</AccordionComponent>
);
}Use Cases:
- Initialize data or state based on component readiness
- Set up event listeners on the component
- Load initial data from external sources
- Trigger animations or transitions
- Track component creation for analytics
Destroyed Event
Fires when the component gets destroyed and removed from DOM.
export default function App() {
const onDestroyed = () => {
console.log('Accordion has been destroyed');
// Clean up resources, remove listeners, etc.
};
return (
<AccordionComponent destroyed={onDestroyed}>
{/* accordion items */}
</AccordionComponent>
);
}Use Cases:
- Clean up event listeners
- Release memory and resources
- Stop timers or intervals
- Persist user state before removal
- Disconnect from external services
Expand/Collapse Events
The Accordion fires events before and after expand/collapse actions, allowing you to validate, prevent, or respond to state changes.
Expanding Event (Before Action)
Fires before an accordion item is expanded or collapsed. Use this to prevent the action.
import React, { useRef } from 'react';
import { ExpandEventArgs } from '@syncfusion/ej2-navigations';
export default function App() {
const accordionRef = useRef(null);
const onExpanding = (args: ExpandEventArgs) => {
console.log('Event Type:', args.name); // 'expanding'
console.log('Item Index:', args.index); // Index of item
console.log('Is Expanding?', args.isExpanded); // true = expanding, false = collapsing
console.log('Item Element:', args.item); // DOM element
// Prevent specific item from collapsing
if (args.index === 0 && !args.isExpanded) {
args.cancel = true; // Prevent collapse
console.log('Item 0 cannot be collapsed');
}
};
return (
<AccordionComponent ref={accordionRef} expanding={onExpanding}>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='Always Open'
content='Cannot collapse this item'
/>
<AccordionItemDirective
header='Can Toggle'
content='This can expand and collapse'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}args Properties:
name- Event name ('expanding')index- Item index being expanded/collapsedisExpanded- true if expanding, false if collapsingitem- The accordion item elementcontent- Content elementheader- Header elementisInteracted- true if user-triggered, false if programmaticcancel- Set to true to prevent the action
Use Cases:
- Validate before allowing collapse (keep at least one open)
- Prevent expanding/collapsing certain items
- Load content dynamically before expansion
- Track user interactions for analytics
- Implement custom expand/collapse logic
Expanded Event (After Action)
Fires after an accordion item has been expanded or collapsed. Use this to respond to state changes.
import React, { useState, useRef } from 'react';
import { ExpandedEventArgs } from '@syncfusion/ej2-navigations';
export default function App() {
const [expandedItems, setExpandedItems] = useState([]);
const onExpanded = (args: ExpandedEventArgs) => {
console.log('Event Type:', args.name); // 'expanded'
console.log('Item Index:', args.index); // Index of item
console.log('Is Now Expanded?', args.isExpanded); // true = expanded, false = collapsed
if (args.isExpanded) {
setExpandedItems(prev =>
prev.includes(args.index) ? prev : [...prev, args.index]
);
} else {
setExpandedItems(prev => prev.filter(i => i !== args.index));
}
};
return (
<div>
<p>Currently expanded items: {expandedItems.join(', ')}</p>
<AccordionComponent expanded={onExpanded}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}args Properties:
name- Event name ('expanded')index- Item index that was expanded/collapsedisExpanded- true if item is now expanded, false if collapseditem- The accordion item elementcontent- Content elementheader- Header elementisInteracted- true if user-triggered
Use Cases:
- Update UI based on expanded state
- Save user preferences
- Load or display related content
- Trigger animations or transitions
- Sync with parent component state
- Log user interactions
Click Events
Clicked Event
Fires whenever the user clicks anywhere within the Accordion component.
import React, { useRef } from 'react';
import { AccordionClickArgs } from '@syncfusion/ej2-navigations';
export default function App() {
const accordionRef = useRef(null);
const onClicked = (args: AccordionClickArgs) => {
console.log('Event Type:', args.name); // 'clicked'
console.log('Event Target:', args.originalEvent.target); // Clicked element
console.log('Item Index:', args.item); // Index of item clicked
// Detect what was clicked
const target = args.originalEvent.target as HTMLElement;
if (target.closest('.e-accordion-header')) {
console.log('Header was clicked');
} else if (target.closest('.e-accordion-content')) {
console.log('Content area was clicked');
}
};
return (
<AccordionComponent ref={accordionRef} clicked={onClicked}>
<AccordionItemsDirective>
<AccordionItemDirective
header='Click anywhere'
content='Click to see events'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}args Properties:
name- Event name ('clicked')originalEvent- Native browser eventitem- Index of clicked itemelement- DOM element that was clicked
Use Cases:
- Track all user interactions
- Implement custom click handling
- Detect header vs content clicks
- Enable right-click context menus
- Implement drag-and-drop
- Analytics and user tracking
Event Arguments Reference
ExpandEventArgs (expanding event)
{
name: 'expanding';
index: number; // 0-based index of item
isExpanded: boolean; // true = expanding, false = collapsing
item: AccordionItemModel; // Item object
content: HTMLElement; // Content DOM element
header: HTMLElement; // Header DOM element
isInteracted: boolean; // User action vs programmatic
cancel: boolean; // Set true to prevent action
}ExpandedEventArgs (expanded event)
{
name: 'expanded';
index: number; // 0-based index of item
isExpanded: boolean; // true = expanded, false = collapsed
item: AccordionItemModel; // Item object
content: HTMLElement; // Content DOM element
header: HTMLElement; // Header DOM element
isInteracted: boolean; // User action vs programmatic
}AccordionClickArgs (clicked event)
{
name: 'clicked';
originalEvent: MouseEvent; // Native browser event
item: number; // Item index
element: HTMLElement; // Clicked element
}Real-World Event Patterns
Pattern 1: Keep One Panel Always Open
Prevent the last open panel from closing in Single mode:
import React, { useRef, useState } from 'react';
import { ExpandEventArgs } from '@syncfusion/ej2-navigations';
export default function App() {
const accordionRef = useRef(null);
const [clickTarget, setClickTarget] = useState(null);
const onExpanding = (args: ExpandEventArgs) => {
if (!args.isExpanded) { // Trying to collapse
const expandedCount = accordionRef.current?.element
.querySelectorAll('.e-selected').length || 0;
if (expandedCount === 1 && clickTarget === args.header) {
args.cancel = true; // Prevent last open panel from closing
}
}
};
const onClicked = (args: AccordionClickArgs) => {
setClickTarget(args.originalEvent.target.closest('.e-accordion-header'));
};
return (
<AccordionComponent
ref={accordionRef}
expandMode='Single'
expanding={onExpanding}
clicked={onClicked}
>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='Always Open'
content='At least one panel must stay open'
/>
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
);
}Pattern 2: Dynamic Content Loading on Expand
Load content from API only when panel expands:
import React, { useRef, useState } from 'react';
import { ExpandedEventArgs } from '@syncfusion/ej2-navigations';
export default function App() {
const accordionRef = useRef(null);
const [contentCache, setContentCache] = useState({});
const [loading, setLoading] = useState({});
const onExpanded = async (args: ExpandedEventArgs) => {
if (args.isExpanded && !contentCache[args.index]) {
setLoading(prev => ({ ...prev, [args.index]: true }));
try {
const response = await fetch(`/api/content/${args.index}`);
const data = await response.json();
setContentCache(prev => ({
...prev,
[args.index]: data.content
}));
} catch (error) {
console.error('Failed to load content:', error);
} finally {
setLoading(prev => ({ ...prev, [args.index]: false }));
}
}
};
return (
<AccordionComponent expanded={onExpanded}>
<AccordionItemsDirective>
<AccordionItemDirective
header='Lazy Load 1'
content={() => (
<>
{loading[0] && <p>Loading...</p>}
{contentCache[0] && <p>{contentCache[0]}</p>}
</>
)}
/>
<AccordionItemDirective
header='Lazy Load 2'
content={() => (
<>
{loading[1] && <p>Loading...</p>}
{contentCache[1] && <p>{contentCache[1]}</p>}
</>
)}
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Pattern 3: Custom Expand/Collapse Sequence
Use events to customize expand/collapse behavior:
import React, { useRef, useState } from 'react';
export default function App() {
const accordionRef = useRef(null);
let isCollapsed = false;
let expandIndex = null;
const onExpanding = (args) => {
if (args.isExpanded && !isCollapsed) {
args.cancel = true;
expandIndex = accordionRef.current.items.indexOf(args.item);
isCollapsed = true;
}
};
const onExpanded = (args) => {
if (!args.isExpanded && isCollapsed) {
accordionRef.current.expandItem(true, expandIndex);
isCollapsed = false;
}
};
return (
<AccordionComponent
ref={accordionRef}
expandMode='Single'
expanding={onExpanding}
expanded={onExpanded}
>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
);
}Preventing Default Actions
Using args.cancel
Set args.cancel = true in the expanding event to prevent the action:
const onExpanding = (args: ExpandEventArgs) => {
// Prevent specific index from expanding
if (args.index === 2) {
args.cancel = true;
}
};Conditional Prevention
const onExpanding = (args: ExpandEventArgs) => {
// Only allow expanding (prevent collapsing)
if (!args.isExpanded) {
args.cancel = true;
}
};Validation-Based Prevention
const onExpanding = (args: ExpandEventArgs) => {
// Check some condition before allowing
if (!userHasPermission && args.index === 0) {
args.cancel = true;
alert('You do not have permission to view this section');
}
};---
Troubleshooting
Issue: Events not firing
- Verify event handler is attached correctly
- Check event name spelling (created vs create)
- Ensure handler function accepts args parameter
Issue: Cannot prevent expand/collapse
- Use
expandingevent, notexpanded(only expanding allows cancel) - Verify
args.cancel = trueis set - Check browser console for errors
Issue: State not updating after event
- Use state management (useState) if updating component state
- Ensure event handler is properly bound
- Check if component is re-rendering
Issue: Memory leaks from event listeners
- Use proper cleanup if attaching DOM listeners
- Remove listeners on component destroy
- Be cautious with closures in event handlers
Expand Modes
Table of Contents
- Overview
- Single Expand Mode
- Multiple Expand Mode
- Setting Initial Expanded State
- Toggle Behavior
- Use Cases
- Comparison
Overview
The Accordion component supports two expand modes that control how many panels can be expanded simultaneously:
- Single - Only one panel can be open at a time
- Multiple - Multiple panels can be open at the same time (default)
Choose the mode based on your UI/UX requirements and content organization strategy.
Single Expand Mode
In Single mode, expanding a new panel automatically collapses the previously expanded panel.
Basic Implementation
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
return (
<AccordionComponent expandMode='Single'>
<AccordionItemsDirective>
<AccordionItemDirective header='Question 1' content='Answer to question 1' />
<AccordionItemDirective header='Question 2' content='Answer to question 2' />
<AccordionItemDirective header='Question 3' content='Answer to question 3' />
</AccordionItemsDirective>
</AccordionComponent>
);
}Behavior Example
1. User clicks "Question 1" → Panel 1 expands 2. User clicks "Question 2" → Panel 1 collapses, Panel 2 expands 3. User clicks "Question 2" again → Panel 2 collapses (toggle) 4. No panels are forced to stay expanded
Single Mode Characteristics
- One panel at a time - Only single panel can be expanded
- Auto-collapse - Previous panel collapses when new one opens
- Toggle support - Click expanded header again to collapse it
- Space efficient - Shows minimal content, maximizes available space
- Focused UX - Guides user through content sequentially
When User Needs Single Mode
Use Single expand mode for:
- FAQ sections - One question/answer visible at a time
- Guided tours - Present information step-by-step
- Menu navigation - Tree-like hierarchical menus
- Sequential workflows - Multi-step processes
- Mobile-friendly layouts - Conserves screen real estate
Multiple Expand Mode
In Multiple mode (default), multiple panels can be expanded at the same time. Users can expand additional panels without collapsing previously expanded ones.
Basic Implementation
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
return (
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective header='Feature 1' content='Details about feature 1' />
<AccordionItemDirective header='Feature 2' content='Details about feature 2' />
<AccordionItemDirective header='Feature 3' content='Details about feature 3' />
</AccordionItemsDirective>
</AccordionComponent>
);
}Behavior Example
1. User clicks "Feature 1" → Panel 1 expands 2. User clicks "Feature 2" → Panel 1 stays expanded, Panel 2 also expands 3. User clicks "Feature 2" again → Panel 2 collapses (Panel 1 remains expanded) 4. Multiple panels can remain expanded indefinitely
Multiple Mode Characteristics
- Multiple panels expanded - Any number of panels can be open
- Independence - Each panel expands/collapses independently
- Toggle support - Click expanded header to collapse without affecting others
- Content visibility - Show all related content simultaneously
- Natural interaction - Users control what they view
When User Needs Multiple Mode
Use Multiple expand mode for:
- Settings panels - Review multiple configuration options at once
- Feature showcase - Display multiple capabilities together
- Dashboard sections - View multiple data widgets simultaneously
- Comparison layouts - See multiple items side-by-side
- Form sections - Preview related form fields together
- Content organization - Browse topics without forced navigation
Setting Initial Expanded State
Use the expanded property to pre-expand specific panels on component load.
Single Pre-expanded Panel
<AccordionComponent expandMode='Single'>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='Getting Started'
content='This section opens by default when component loads.'
/>
<AccordionItemDirective header='Advanced Usage' content='Revealed when user clicks.' />
<AccordionItemDirective header='API Reference' content='Revealed when user clicks.' />
</AccordionItemsDirective>
</AccordionComponent>Result: "Getting Started" is expanded on page load; others are collapsed
Multiple Pre-expanded Panels
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='Installation'
content='Installation instructions...'
/>
<AccordionItemDirective
expanded={true}
header='Quick Start'
content='Quick start guide...'
/>
<AccordionItemDirective
header='Examples'
content='More examples...'
/>
</AccordionItemsDirective>
</AccordionComponent>Result: "Installation" and "Quick Start" are expanded on load; "Examples" collapsed
Conditional Expanded State
Pre-expand panels based on component state:
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [isNewUser, setIsNewUser] = useState(true);
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={isNewUser}
header='New User Guide'
content='Step-by-step guide for new users...'
/>
<AccordionItemDirective
expanded={!isNewUser}
header='Advanced Options'
content='For experienced users...'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Behavior: Shows different sections based on user type
Toggle Behavior
Toggle functionality allows users to click an expanded header to collapse it.
Default Toggle Behavior
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='Click Me'
content='Content here'
/>
</AccordionItemsDirective>
</AccordionComponent>User interactions:
- First click on header → Expands if collapsed
- Second click on header → Collapses if expanded
- Third click on header → Expands again
This works in both Single and Multiple modes.
Toggle in Single Mode
In Single mode, toggle behavior is enhanced:
<AccordionComponent expandMode='Single'>
<AccordionItemsDirective>
<AccordionItemDirective expanded={true} header='Section 1' content='...' />
<AccordionItemDirective header='Section 2' content='...' />
<AccordionItemDirective header='Section 3' content='...' />
</AccordionItemsDirective>
</AccordionComponent>Interaction flow: 1. Section 1 starts expanded 2. Click Section 2 → Section 1 collapses, Section 2 expands 3. Click Section 1 → Section 2 collapses, Section 1 expands 4. Click Section 1 again → Section 1 collapses (all sections closed)
Toggle in Multiple Mode
In Multiple mode, each panel toggles independently:
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective expanded={true} header='Section 1' content='...' />
<AccordionItemDirective expanded={true} header='Section 2' content='...' />
<AccordionItemDirective header='Section 3' content='...' />
</AccordionItemsDirective>
</AccordionComponent>Interaction flow: 1. Sections 1 and 2 start expanded 2. Click Section 1 → Section 1 collapses (Section 2 stays expanded) 3. Click Section 3 → Section 3 expands (Sections 1 and 2 remain in their states) 4. Multiple panels can remain expanded
Use Cases
FAQ Section (Single Mode Recommended)
<AccordionComponent expandMode='Single'>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='How do I get started?'
content='Visit our getting started guide...'
/>
<AccordionItemDirective
header='What are the pricing options?'
content='We offer three pricing tiers...'
/>
<AccordionItemDirective
header='Is there a free trial?'
content='Yes, we offer a 14-day free trial...'
/>
</AccordionItemsDirective>
</AccordionComponent>Why Single Mode: Users browse one question at a time, focusing on relevant information
Settings Panel (Multiple Mode Recommended)
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='Account Settings'
content='Email, password, 2FA options...'
/>
<AccordionItemDirective
expanded={true}
header='Notification Preferences'
content='Email alerts, SMS notifications...'
/>
<AccordionItemDirective
header='Privacy & Security'
content='Data sharing, security logs...'
/>
</AccordionItemsDirective>
</AccordionComponent>Why Multiple Mode: Users review multiple settings simultaneously before saving changes
Comparison
| Aspect | Single Mode | Multiple Mode |
|---|---|---|
| Panels Open | One at a time | Multiple simultaneously |
| Default Behavior | Auto-collapse previous | Independent panels |
| Use Case | FAQs, Step-by-step guides | Settings, Dashboards |
| Space Efficient | Yes | No (shows more content) |
| User Control | Guided (one section) | Full control (view all) |
| Toggle Click | Can collapse to empty state | Toggles individual panels |
| Initial Expanded | Set one default | Can set multiple defaults |
---
Troubleshooting
Issue: Multiple panels collapse unexpectedly
- Verify
expandMode='Multiple'is set correctly - Check that
expanded={true}doesn't override mode behavior - Inspect component state for conflicts
Issue: Single mode not auto-collapsing
- Confirm
expandMode='Single'is specified - Check for custom event handlers overriding default behavior
Issue: Can't collapse all panels in Single mode
- This is by-design - toggle behavior allows all-collapsed state
- Click expanded header again to collapse
Issue: Pre-expanded state not working
- Ensure
expanded={true}is onAccordionItemDirective - Verify it's not being overridden by component state
- Check browser console for React state conflicts
Getting Started with Accordion
Table of Contents
- Installation
- CSS Imports
- Basic Setup
- Initialization Methods
- Minimal Working Example
- Item Configuration
- Tracking Expanded Items with expandedIndices
- Customizing Headers with headerTemplate
- Customizing Appearance
Installation
Install the Syncfusion React navigations package using npm:
npm install @syncfusion/ej2-react-navigations --saveThis package includes the Accordion component and its dependencies:
@syncfusion/ej2-base- Core utilities@syncfusion/ej2-react-base- React bindings@syncfusion/ej2-navigations- Navigation components@syncfusion/ej2-buttons- Button component (used by headers)@syncfusion/ej2-popups- Popup utilities
CSS Imports
Add component styles to your application. Choose the theme that matches your design:
/* In your App.css or App.tsx */
@import '../node_modules/@syncfusion/ej2-base/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css';
@import '../node_modules/@syncfusion/ej2-react-navigations/styles/tailwind3.css';Available Themes:
tailwind3.css- Modern Tailwind designbootstrap5.3.css- Bootstrap 5.3 stylingfluent2.css- Microsoft Fluent 2 designmaterial3.css- Material Design 3
Then import the CSS file in your React component:
import './App.css';Basic Setup
Import the Accordion component and required directives:
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';These three components work together:
AccordionComponent- Main containerAccordionItemsDirective- Wrapper for itemsAccordionItemDirective- Individual collapsible panels
Initialization Methods
Method 1: Using Items API (Recommended)
Declare accordion items using component directives:
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
import './App.css';
export default function App() {
const aspContent = () => (
<div>Microsoft ASP.NET is a set of technologies for building Web applications.</div>
);
const mvcContent = () => (
<div>The Model-View-Controller (MVC) architectural pattern separates an application into three main components.</div>
);
const jsContent = () => (
<div>JavaScript (JS) is an interpreted computer programming language.</div>
);
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective header='ASP.NET' content={aspContent} />
<AccordionItemDirective header='ASP.NET MVC' content={mvcContent} />
<AccordionItemDirective header='JavaScript' content={jsContent} />
</AccordionItemsDirective>
</AccordionComponent>
);
}Benefits: Clear component structure, easy to manage state, preferred for React applications
Method 2: Using HTML Markup
Use native HTML elements as accordion structure:
import React from 'react';
import { AccordionComponent } from '@syncfusion/ej2-react-navigations';
import './App.css';
export default function App() {
return (
<AccordionComponent>
<div>
<div>
<div>ASP.NET</div>
</div>
<div>
<div>Microsoft ASP.NET is a set of technologies...</div>
</div>
</div>
<div>
<div>
<div>ASP.NET MVC</div>
</div>
<div>
<div>The Model-View-Controller (MVC) architectural pattern...</div>
</div>
</div>
</AccordionComponent>
);
}HTML Structure:
AccordionComponent
└─ div (item container)
├─ div (header container)
│ └─ div (header text/content)
└─ div (panel container)
└─ div (panel content)When to use: For simple static content or migrating from HTML-based templates
Minimal Working Example
Complete working example with two collapsible panels:
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
import '@syncfusion/ej2-base/styles/tailwind3.css';
import '@syncfusion/ej2-buttons/styles/tailwind3.css';
import '@syncfusion/ej2-popups/styles/tailwind3.css';
import '@syncfusion/ej2-react-navigations/styles/tailwind3.css';
export default function App() {
return (
<div className='p-8'>
<h1>My First Accordion</h1>
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective
header='What is React?'
content='React is a JavaScript library for building user interfaces with reusable components.'
/>
<AccordionItemDirective
header='What is JSX?'
content='JSX is a syntax extension that allows you to write HTML-like code in JavaScript.'
/>
<AccordionItemDirective
header='What are Hooks?'
content='Hooks are functions that let you "hook into" React state and lifecycle features.'
/>
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Run the application:
npm run devThe accordion will render with three collapsible panels, all initially collapsed. Click headers to expand/collapse.
Item Configuration
Each accordion item can be configured with specific properties to control its appearance, behavior, and state.
Item Properties Reference
| Property | Type | Default | Description |
|---|---|---|---|
header | string | - | Header text or JSX component for the panel header |
content | string \ | JSX | - |
expanded | boolean | false | Whether the item is initially expanded |
disabled | boolean | false | Whether the item is disabled and cannot be clicked |
cssClass | string | - | Custom CSS class to apply to the item |
Basic Item Configuration
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
return (
<AccordionComponent>
<AccordionItemsDirective>
{/* Initially expanded item */}
<AccordionItemDirective
header='Always Open'
content='This item starts expanded'
expanded={true}
/>
{/* Disabled item */}
<AccordionItemDirective
header='Locked Section'
content='This item is disabled and cannot be clicked'
disabled={true}
/>
{/* Normal item */}
<AccordionItemDirective
header='Regular Item'
content='This is a normal collapsible item'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Setting Per-Item Initial Expansion
Use the expanded property to control which items are open when the component loads:
<AccordionComponent expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective
expanded={true}
header='Expanded by Default'
content='This panel opens automatically'
/>
<AccordionItemDirective
expanded={true}
header='Also Expanded'
content='Multiple items can be open with Multiple mode'
/>
<AccordionItemDirective
expanded={false}
header='Collapsed Item'
content='This one starts closed'
/>
</AccordionItemsDirective>
</AccordionComponent>Disabling Specific Items
Mark items as disabled to prevent user interaction:
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
header='Available'
content='User can click this'
/>
<AccordionItemDirective
disabled={true}
header='Coming Soon'
content='This feature will be available soon'
/>
<AccordionItemDirective
disabled={true}
header='Premium Only'
content='This requires a premium subscription'
/>
<AccordionItemDirective
header='Available'
content='User can click this'
/>
</AccordionItemsDirective>
</AccordionComponent>Styling disabled items:
.e-accordion-item.e-disabled .e-accordion-header {
opacity: 0.6;
cursor: not-allowed;
}Applying Custom CSS to Items
Use the cssClass property to style individual items differently:
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
header='Warning Section'
content='This item has special styling'
cssClass='warning-item'
/>
<AccordionItemDirective
header='Success Section'
content='This item indicates success'
cssClass='success-item'
/>
<AccordionItemDirective
header='Info Section'
content='This item shows information'
cssClass='info-item'
/>
</AccordionItemsDirective>
</AccordionComponent>Styling each type:
/* Warning item styling */
.warning-item .e-accordion-header {
background-color: #ff9800;
color: white;
border-left: 4px solid #e65100;
}
.warning-item .e-accordion-content {
background-color: #fff3e0;
border-left: 4px solid #ff9800;
}
/* Success item styling */
.success-item .e-accordion-header {
background-color: #4caf50;
color: white;
border-left: 4px solid #2e7d32;
}
.success-item .e-accordion-content {
background-color: #f1f8e9;
border-left: 4px solid #4caf50;
}
/* Info item styling */
.info-item .e-accordion-header {
background-color: #2196f3;
color: white;
border-left: 4px solid #1565c0;
}
.info-item .e-accordion-content {
background-color: #e3f2fd;
border-left: 4px solid #2196f3;
}Dynamic Item Configuration
Configure items dynamically based on data:
import React, { useState } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const [items] = useState([
{
header: 'FAQ #1',
content: 'First frequently asked question...',
expanded: true,
disabled: false,
cssClass: 'faq-item'
},
{
header: 'FAQ #2',
content: 'Second frequently asked question...',
expanded: false,
disabled: false,
cssClass: 'faq-item'
},
{
header: 'FAQ #3',
content: 'Third frequently asked question...',
expanded: false,
disabled: true,
cssClass: 'faq-item'
}
]);
return (
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item, index) => (
<AccordionItemDirective
key={index}
header={item.header}
content={item.content}
expanded={item.expanded}
disabled={item.disabled}
cssClass={item.cssClass}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Tracking Expanded Items with expandedIndices
The expandedIndices property returns an array of indices for currently expanded items. Use this to track state or control which panels are open.
Getting Currently Expanded Items
import React, { useRef } from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const accordionRef = useRef(null);
const checkExpandedItems = () => {
const expanded = accordionRef.current?.expandedIndices;
console.log('Currently expanded items:', expanded);
// Output example: [0, 2] means items at index 0 and 2 are expanded
};
return (
<div>
<button onClick={checkExpandedItems}>Check Expanded Items</button>
<AccordionComponent ref={accordionRef} expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Using expandedIndices in Events
import React, { useRef, useState } from 'react';
import { ExpandedEventArgs } from '@syncfusion/ej2-navigations';
export default function App() {
const accordionRef = useRef(null);
const [expandedList, setExpandedList] = useState([]);
const onExpanded = (args: ExpandedEventArgs) => {
const expanded = accordionRef.current?.expandedIndices || [];
setExpandedList(expanded);
console.log('Expanded indices after change:', expanded);
};
return (
<div>
<p>Expanded items: [{expandedList.join(', ')}]</p>
<AccordionComponent ref={accordionRef} expanded={onExpanded} expandMode='Multiple'>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Content 1' />
<AccordionItemDirective header='Item 2' content='Content 2' />
<AccordionItemDirective header='Item 3' content='Content 3' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Wizard Pattern with expandedIndices
Real-world example using expandedIndices to control a multi-step wizard:
import React, { useRef } from 'react';
export default function App() {
const accordionRef = useRef(null);
const allowNext = (): boolean => {
const expanded = accordionRef.current?.expandedIndices || [];
// Only allow moving to next step if current step is complete
return expanded[expanded.length - 1] >= 0;
};
const goToStep = (stepIndex: number) => {
accordionRef.current?.expandItem(true, stepIndex);
};
return (
<div>
<div style={{ marginBottom: '15px' }}>
<button onClick={() => goToStep(0)}>Step 1: Signin</button>
<button onClick={() => goToStep(1)} disabled={!allowNext()}>
Step 2: Address
</button>
<button onClick={() => goToStep(2)} disabled={!allowNext()}>
Step 3: Payment
</button>
</div>
<AccordionComponent ref={accordionRef} expandMode='Single'>
<AccordionItemsDirective>
<AccordionItemDirective expanded={true} header='Sign In' content='Email and password...' />
<AccordionItemDirective header='Delivery Address' content='Address details...' />
<AccordionItemDirective header='Card Details' content='Payment information...' />
</AccordionItemsDirective>
</AccordionComponent>
</div>
);
}Setting Initial expandedIndices
Set which items should be expanded when the component loads:
<AccordionComponent expandMode='Multiple' expandedIndices={[0, 2]}>
<AccordionItemsDirective>
<AccordionItemDirective header='Item 1' content='Expanded on load' />
<AccordionItemDirective header='Item 2' content='Collapsed on load' />
<AccordionItemDirective header='Item 3' content='Expanded on load' />
</AccordionItemsDirective>
</AccordionComponent>Customizing Headers with headerTemplate
The headerTemplate property allows you to render custom JSX or components as accordion headers instead of plain text.
Basic Header Template
import React from 'react';
import {
AccordionComponent,
AccordionItemDirective,
AccordionItemsDirective
} from '@syncfusion/ej2-react-navigations';
export default function App() {
const customHeader1 = () => (
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<span style={{ fontSize: '20px' }}>📋</span>
<span>Document List</span>
</div>
);
const customHeader2 = () => (
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<span style={{ fontSize: '20px' }}>⚙️</span>
<span>Settings</span>
</div>
);
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
headerTemplate={customHeader1}
content='List of documents here'
/>
<AccordionItemDirective
headerTemplate={customHeader2}
content='Configuration settings here'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Header Template with Status Badge
const headerWithBadge = () => (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span>User Information</span>
<span
style={{
backgroundColor: '#4caf50',
color: 'white',
padding: '2px 8px',
borderRadius: '12px',
fontSize: '12px'
}}
>
Complete
</span>
</div>
);
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
headerTemplate={headerWithBadge}
content='User details form'
/>
</AccordionItemsDirective>
</AccordionComponent>Header Template with Dynamic Data
import React, { useState } from 'react';
export default function App() {
const [items] = useState([
{ id: 1, title: 'Task 1', status: 'pending', priority: 'high' },
{ id: 2, title: 'Task 2', status: 'in-progress', priority: 'medium' },
{ id: 3, title: 'Task 3', status: 'completed', priority: 'low' }
]);
const getStatusColor = (status: string) => {
const colors = {
'pending': '#ff9800',
'in-progress': '#2196f3',
'completed': '#4caf50'
};
return colors[status] || '#999';
};
const taskHeader = (item) => (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }}>
<div>
<strong>{item.title}</strong>
<span style={{ marginLeft: '10px', fontSize: '12px', color: '#666' }}>
Priority: {item.priority}
</span>
</div>
<span
style={{
backgroundColor: getStatusColor(item.status),
color: 'white',
padding: '4px 12px',
borderRadius: '4px',
fontSize: '12px'
}}
>
{item.status}
</span>
</div>
);
return (
<AccordionComponent>
<AccordionItemsDirective>
{items.map((item) => (
<AccordionItemDirective
key={item.id}
headerTemplate={() => taskHeader(item)}
content={`Details for ${item.title}`}
/>
))}
</AccordionItemsDirective>
</AccordionComponent>
);
}Header Template with Syncfusion Components
import React from 'react';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { ChipListComponent } from '@syncfusion/ej2-react-buttons';
export default function App() {
const advancedHeader = () => (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<div>
<h4>Advanced Settings</h4>
<small>Configure component behavior</small>
</div>
<ButtonComponent cssClass='e-small'>Edit</ButtonComponent>
</div>
);
return (
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
headerTemplate={advancedHeader}
content='Settings configuration here'
/>
</AccordionItemsDirective>
</AccordionComponent>
);
}Header Template with Icons and Counters
const headerWithCounter = (label: string, count: number) => (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span>{label}</span>
<span
style={{
backgroundColor: '#f0f0f0',
padding: '2px 8px',
borderRadius: '50%',
minWidth: '24px',
textAlign: 'center',
fontWeight: 'bold'
}}
>
{count}
</span>
</div>
);
<AccordionComponent>
<AccordionItemsDirective>
<AccordionItemDirective
headerTemplate={() => headerWithCounter('Notifications', 5)}
content='List of 5 notifications'
/>
<AccordionItemDirective
headerTemplate={() => headerWithCounter('Messages', 12)}
content='List of 12 messages'
/>
<AccordionItemDirective
headerTemplate={() => headerWithCounter('Tasks', 3)}
content='List of 3 tasks'
/>
</AccordionItemsDirective>
</AccordionComponent>Customizing Appearance
Adding Custom CSS Classes
Use the cssClass property to apply custom styles:
<AccordionComponent cssClass='custom-accordion'>
<AccordionItemsDirective>
<AccordionItemDirective
header='Section 1'
content='Content here'
cssClass='custom-item'
/>
</AccordionItemsDirective>
</AccordionComponent>Then style in your CSS:
.custom-accordion {
background-color: #f5f5f5;
border-radius: 8px;
}
.custom-item .e-accordion-header {
background-color: #007bff;
color: white;
font-weight: bold;
}
.custom-item .e-accordion-content {
padding: 20px;
}Using Built-in Classes
The Accordion generates these classes automatically:
.e-accordion /* Main container */
.e-accordion-item /* Individual item */
.e-accordion-header /* Header section */
.e-accordion-content /* Content panel */
.e-accordion-control /* Expanded item */
.e-disabled /* Disabled item */Common Styling Tasks
Change header background:
.e-accordion-header {
background-color: #2c3e50;
color: white;
}Add padding to content:
.e-accordion-content {
padding: 20px 15px;
}Customize borders:
.e-accordion-item {
border: 1px solid #ddd;
margin: 10px 0;
}---
Next Steps
1. Expand Modes - Control whether one or multiple panels can be open 2. Animation Effects - Add smooth transitions when panels expand/collapse 3. Content Loading - Load content dynamically from data sources or APIs 4. Advanced Features - Nested accordions, events, and React hooks patterns
Troubleshooting
Issue: Styles not appearing
- Verify all CSS imports are present in correct order
- Check that theme CSS file matches your chosen theme
- Ensure CSS file is imported before component usage
Issue: Component not rendering
- Confirm package is installed:
npm list @syncfusion/ej2-react-navigations - Check that component imports match your component names
- Verify React version compatibility
Issue: Content not showing
- For Items API: ensure
contentprop is provided - For HTML markup: verify DOM structure follows required hierarchy
- Check browser console for errors